summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cpu/cpu.c61
-rw-r--r--kernel/cpu/idt.S121
-rw-r--r--kernel/cpu/idt.c44
-rw-r--r--kernel/cpu/tss.S6
-rw-r--r--kernel/cpu/tss.c82
-rw-r--r--kernel/cpu/tss.h31
-rw-r--r--kernel/drivers.c4
-rw-r--r--kernel/drivers/ata.c18
-rw-r--r--kernel/drivers/gpu.c2
-rw-r--r--kernel/drivers/gpu/bochs.c4
-rw-r--r--kernel/drivers/gpu/gop.c4
-rw-r--r--kernel/drivers/pit.c9
-rw-r--r--kernel/drivers/ps2.c268
-rw-r--r--kernel/entry.S5
-rw-r--r--kernel/fs/fs.c31
-rw-r--r--kernel/include/comus/asm.h6
-rw-r--r--kernel/include/comus/cpu.h12
-rw-r--r--kernel/include/comus/drivers/ata.h4
-rw-r--r--kernel/include/comus/drivers/gpu.h4
-rw-r--r--kernel/include/comus/drivers/gpu/bochs.h2
-rw-r--r--kernel/include/comus/drivers/gpu/gop.h2
-rw-r--r--kernel/include/comus/drivers/ps2.h27
-rw-r--r--kernel/include/comus/fs.h151
-rw-r--r--kernel/include/comus/input.h36
-rw-r--r--kernel/include/comus/keycodes.h138
-rw-r--r--kernel/include/comus/limits.h8
-rw-r--r--kernel/include/comus/memory.h38
-rw-r--r--kernel/include/comus/procs.h35
-rw-r--r--kernel/include/comus/syscalls.h5
-rw-r--r--kernel/include/comus/user.h30
-rw-r--r--kernel/include/lib.h1
-rw-r--r--kernel/include/lib/kmath.h20
-rw-r--r--kernel/input.c93
-rw-r--r--kernel/lib/backtrace.c15
-rw-r--r--kernel/lib/kalloc.c3
-rw-r--r--kernel/lib/memcmp.c2
-rw-r--r--kernel/lib/memcpy.c2
-rw-r--r--kernel/lib/memmove.c2
-rw-r--r--kernel/lib/memmovev.c3
-rw-r--r--kernel/lib/memset.c2
-rw-r--r--kernel/lib/memsetv.c2
-rw-r--r--kernel/main.c13
-rw-r--r--kernel/memory/memory.c54
-rw-r--r--kernel/memory/paging.c537
-rw-r--r--kernel/memory/paging.h7
-rw-r--r--kernel/memory/physalloc.c93
-rw-r--r--kernel/memory/physalloc.h35
-rw-r--r--kernel/memory/virtalloc.c122
-rw-r--r--kernel/memory/virtalloc.h15
-rw-r--r--kernel/procs.c163
-rw-r--r--kernel/syscall.c374
-rw-r--r--kernel/user.c260
52 files changed, 2540 insertions, 466 deletions
diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c
index 136a1d8..f607b36 100644
--- a/kernel/cpu/cpu.c
+++ b/kernel/cpu/cpu.c
@@ -1,8 +1,10 @@
#include <lib.h>
#include <comus/cpu.h>
+#include <comus/asm.h>
#include "pic.h"
#include "idt.h"
+#include "tss.h"
static inline void fpu_init(void)
{
@@ -60,8 +62,10 @@ void cpu_init(void)
struct cpu_feat feats;
cpu_feats(&feats);
- pic_remap();
+ cli();
idt_init();
+ tss_init();
+ pic_remap();
if (feats.fpu)
fpu_init();
if (feats.sse) {
@@ -178,25 +182,26 @@ void cpu_feats(struct cpu_feat *feats)
void cpu_print_regs(struct cpu_regs *regs)
{
- kprintf("rax: %#016lx (%lu)\n", regs->rax, regs->rax);
- kprintf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx);
- kprintf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx);
- kprintf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx);
- kprintf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi);
- kprintf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi);
- kprintf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp);
- kprintf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp);
- kprintf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8);
- kprintf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9);
- kprintf("r10: %#016lx (%lu)\n", regs->r10, regs->r10);
- kprintf("r11: %#016lx (%lu)\n", regs->r11, regs->r11);
- kprintf("r12: %#016lx (%lu)\n", regs->r12, regs->r12);
- kprintf("r13: %#016lx (%lu)\n", regs->r13, regs->r13);
- kprintf("r14: %#016lx (%lu)\n", regs->r14, regs->r14);
- kprintf("r15: %#016lx (%lu)\n", regs->r15, regs->r15);
- kprintf("rip: %#016lx (%lu)\n", regs->rip, regs->rip);
- kprintf("rflags: %#016lx (%lu)\n", regs->rflags, regs->rflags);
- kputs("rflags: ");
+ kprintf("rax:\t%#016lx (%lu)\n", regs->rax, regs->rax);
+ kprintf("rbx:\t%#016lx (%lu)\n", regs->rbx, regs->rbx);
+ kprintf("rcx:\t%#016lx (%lu)\n", regs->rcx, regs->rcx);
+ kprintf("rdx:\t%#016lx (%lu)\n", regs->rdx, regs->rdx);
+ kprintf("rsi:\t%#016lx (%lu)\n", regs->rsi, regs->rsi);
+ kprintf("rdi:\t%#016lx (%lu)\n", regs->rdi, regs->rdi);
+ kprintf("rsp:\t%#016lx (%lu)\n", regs->rsp, regs->rsp);
+ kprintf("rbp:\t%#016lx (%lu)\n", regs->rbp, regs->rbp);
+ kprintf("r8:\t%#016lx (%lu)\n", regs->r8, regs->r8);
+ kprintf("r9:\t%#016lx (%lu)\n", regs->r9, regs->r9);
+ kprintf("r10:\t%#016lx (%lu)\n", regs->r10, regs->r10);
+ kprintf("r11:\t%#016lx (%lu)\n", regs->r11, regs->r11);
+ kprintf("r12:\t%#016lx (%lu)\n", regs->r12, regs->r12);
+ kprintf("r13:\t%#016lx (%lu)\n", regs->r13, regs->r13);
+ kprintf("r14:\t%#016lx (%lu)\n", regs->r14, regs->r14);
+ kprintf("r15:\t%#016lx (%lu)\n", regs->r15, regs->r15);
+ kprintf("rip:\t%#016lx (%lu)\n", regs->rip, regs->rip);
+ kprintf("rflags: %#016lx (%lu) [ ", regs->rflags, regs->rflags);
+ if (regs->rflags & (3 << 12))
+ kprintf("IOPL=%lu ", (regs->rflags >> 12) & 0x3);
if (regs->rflags & (1 << 0))
kputs("CF ");
if (regs->rflags & (1 << 2))
@@ -215,8 +220,6 @@ void cpu_print_regs(struct cpu_regs *regs)
kputs("DF ");
if (regs->rflags & (1 << 11))
kputs("OF ");
- if (regs->rflags & (3 << 12))
- kputs("IOPL ");
if (regs->rflags & (1 << 14))
kputs("NT ");
if (regs->rflags & (1 << 15))
@@ -233,5 +236,19 @@ void cpu_print_regs(struct cpu_regs *regs)
kputs("VIP ");
if (regs->rflags & (1 << 21))
kputs("ID ");
+ kputs("]\n");
+ kprintf("cs:\t%#04lx (%lu) [ DPL=%lu ]\n", regs->cs, regs->cs,
+ regs->cs & 0x3);
+ kprintf("ss:\t%#04lx (%lu) [ DPL=%lu ]\n", regs->ss, regs->ss,
+ regs->ss & 0x3);
+ kprintf("ds:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->ds, regs->ds,
+ regs->ds & 0x3);
+ kprintf("es:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->es, regs->es,
+ regs->es & 0x3);
+ kprintf("fs:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->fs, regs->fs,
+ regs->fs & 0x3);
+ kprintf("gs:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->gs, regs->gs,
+ regs->gs & 0x3);
+ kprintf("cr3:\t%#016lx (%lu)\n", regs->cr3, regs->cr3);
kputs("\n");
}
diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S
index 0ba35f8..b3a8454 100644
--- a/kernel/cpu/idt.S
+++ b/kernel/cpu/idt.S
@@ -1,12 +1,17 @@
.global isr_stub_table
+ .global syscall_return
.extern idt_exception_handler
.extern idt_pic_timer
.extern idt_pic_keyboard
.extern idt_pic_mouse
.extern idt_pic_eoi
+ .extern syscall_handler
+ .extern current_pcb
+ .extern isr_save
.macro PUSHALL
+ # regs
pushq %rax
pushq %rbx
pushq %rcx
@@ -22,9 +27,38 @@
pushq %r13
pushq %r14
pushq %r15
+
+ # segments
+ movw %ds, %ax
+ pushw %ax
+ movw %es, %ax
+ pushw %ax
+ movw %fs, %ax
+ pushw %ax
+ movw %gs, %ax
+ pushw %ax
+
+ # pgdir
+ movq %cr3, %rax
+ pushq %rax
.endm
.macro POPALL
+ # pgdir
+ popq %rax
+ movq %rax, %cr3
+
+ # segments
+ popw %ax
+ movw %ax, %gs
+ popw %ax
+ movw %ax, %fs
+ popw %ax
+ movw %ax, %es
+ popw %ax
+ movw %ax, %ds
+
+ # regs
popq %r15
popq %r14
popq %r13
@@ -42,19 +76,29 @@
popq %rax
.endm
+.macro ISRSave
+ PUSHALL
+ cld
+
+ movq %rsp, %rdi
+ callq isr_save
+.endm
+
+.macro ISRRestore
+ POPALL
+ iretq
+.endm
+
# call the exception handler with the interrupt number
# args: interrupt number
.macro ISRException num
.align 8
isr_stub_\num:
- PUSHALL
- cld
- movq $\num, %rdi # exception number
+ ISRSave
+ movq $\num, %rdi # exception number
movq $0, %rsi # placeholder error code
- movq %rsp, %rdx # top of stack
callq idt_exception_handler
- POPALL
- iretq
+ ISRRestore
.endm
# call the exception handler with the interrupt number
@@ -64,65 +108,64 @@ isr_stub_\num:
.align 8
isr_stub_\num:
# retrieve the error code without corrupting registers
- mov %eax, isr_tmp
+ movq %rax, isr_tmp
popq %rax
- mov %eax, isr_err_code
+ movq %rax, isr_err_code
movq isr_tmp, %rax
- PUSHALL
- cld
+ ISRSave
movq $\num, %rdi # exception number
movq isr_err_code, %rsi # error code
- movq %rsp, %rdx # top of stack
callq idt_exception_handler
- POPALL
- iretq
+ ISRRestore
+.endm
+
+.macro SYSCALL num
+ .align 8
+isr_stub_\num:
+ ISRSave
+ callq syscall_handler
+ jmp syscall_return
.endm
.macro PICGeneric num
.align 8
isr_stub_\num:
- PUSHALL
- cld
+ ISRSave
movq $\num, %rdi
callq idt_pic_eoi
- POPALL
- iretq
+ ISRRestore
.endm
+# we have to send eoi first since
+# idt_pic_timer may not return
.macro PICTimer num
.align 8
isr_stub_\num:
- PUSHALL
- cld
- callq idt_pic_timer
- movq $\num, %rdi
+ ISRSave
callq idt_pic_eoi
- POPALL
- iretq
+ movq $\num, %rdi
+ callq idt_pic_timer
+ ISRRestore
.endm
.macro PICKeyboard num
.align 8
isr_stub_\num:
- PUSHALL
- cld
+ ISRSave
callq idt_pic_keyboard
movq $\num, %rdi
callq idt_pic_eoi
- POPALL
- iretq
+ ISRRestore
.endm
.macro PICMouse num
.align 8
isr_stub_\num:
- PUSHALL
- cld
+ ISRSave
callq idt_pic_mouse
movq $\num, %rdi
callq idt_pic_eoi
- POPALL
- iretq
+ ISRRestore
.endm
# do nothing
@@ -402,10 +445,22 @@ isr_stub_table:
.quad isr_stub_254
.quad isr_stub_255
-# isr stubs
.section .text
.code64
+# isr restore
+syscall_return:
+ // get current pcb address
+ movq current_pcb, %rbx
+
+ // load user stack
+ leaq 8(%rbx), %rsp
+
+ // return
+ POPALL
+ iretq
+
+# isr stubs
ISRException 0
ISRException 1
ISRException 2
@@ -536,7 +591,7 @@ ISRIgnore 124
ISRIgnore 125
ISRIgnore 126
ISRIgnore 127
-ISRIgnore 128
+SYSCALL 128
ISRIgnore 129
ISRIgnore 130
ISRIgnore 131
diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c
index bf4b499..2eab7ec 100644
--- a/kernel/cpu/idt.c
+++ b/kernel/cpu/idt.c
@@ -2,7 +2,10 @@
#include <comus/memory.h>
#include <comus/asm.h>
#include <comus/cpu.h>
+#include <comus/drivers/ps2.h>
#include <comus/drivers/pit.h>
+#include <comus/procs.h>
+#include <comus/memory.h>
#include "idt.h"
#include "pic.h"
@@ -41,8 +44,12 @@ struct idtr {
__attribute__((aligned(0x10))) static struct idt_entry idt[256];
static struct idtr idtr;
-// from idt.S
extern void *isr_stub_table[];
+extern char kern_stack_start[];
+extern char kern_stack_end[];
+
+// current register state on interrupt
+static struct cpu_regs *state;
// initialize and load the IDT
void idt_init(void)
@@ -57,15 +64,17 @@ void idt_init(void)
uint64_t isr = (uint64_t)isr_stub_table[vector];
// interrupts before 0x20 are for cpu exceptions
- uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT;
entry->kernel_cs = 0x08; // offset of 1 into GDT
entry->ist = 0;
- entry->flags = PRESENT | RING0 | gate_type;
+ entry->flags = PRESENT | RING0 | GATE_64BIT_INT;
entry->isr_low = isr & 0xffff;
entry->isr_mid = (isr >> 16) & 0xffff;
entry->isr_high = (isr >> 32) & 0xffffffff;
entry->reserved = 0;
+
+ if (vector == 0x80)
+ entry->flags |= RING3;
}
__asm__ volatile("lidt %0" : : "m"(idtr));
@@ -111,8 +120,8 @@ char *EXCEPTIONS[] = {
"Reserved",
};
-void idt_exception_handler(uint64_t exception, uint64_t code,
- struct cpu_regs *state)
+__attribute__((noreturn)) void idt_exception_handler(uint64_t exception,
+ uint64_t code)
{
uint64_t cr2;
@@ -144,22 +153,43 @@ void idt_exception_handler(uint64_t exception, uint64_t code,
}
}
+void isr_save(struct cpu_regs *regs)
+{
+ // make sure were in the kernel memory context
+ mem_ctx_switch(kernel_mem_ctx);
+
+ // save pointer to registers
+ state = regs;
+
+ // if we have a kernel stack pointer
+ // we should return to not save kernel context
+ // data to userspace
+ if (regs->rsp >= (size_t)kern_stack_start &&
+ regs->rsp <= (size_t)kern_stack_end)
+ return;
+
+ // save registers in current_pcb
+ if (current_pcb != NULL)
+ current_pcb->regs = *regs;
+}
+
void idt_pic_eoi(uint8_t exception)
{
pic_eoi(exception - PIC_REMAP_OFFSET);
}
-int counter = 0;
-
void idt_pic_timer(void)
{
ticks++;
+ pcb_on_tick();
}
void idt_pic_keyboard(void)
{
+ ps2kb_recv();
}
void idt_pic_mouse(void)
{
+ ps2mouse_recv();
}
diff --git a/kernel/cpu/tss.S b/kernel/cpu/tss.S
new file mode 100644
index 0000000..27f2955
--- /dev/null
+++ b/kernel/cpu/tss.S
@@ -0,0 +1,6 @@
+ .globl tss_flush
+
+tss_flush:
+ movw $0x28, %ax
+ ltr %ax
+ ret
diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c
new file mode 100644
index 0000000..bca979d
--- /dev/null
+++ b/kernel/cpu/tss.c
@@ -0,0 +1,82 @@
+#include <comus/memory.h>
+#include <lib.h>
+
+#include "tss.h"
+
+struct sys_seg_descriptor {
+ uint64_t limit0_15 : 16;
+ uint64_t base0_15 : 16;
+ uint64_t base16_23 : 8;
+ uint64_t type : 4;
+ uint64_t : 1;
+ uint64_t DPL : 2;
+ uint64_t present : 1;
+ uint64_t limit16_19 : 4;
+ uint64_t available : 1;
+ uint64_t : 1;
+ uint64_t : 1;
+ uint64_t gran : 1;
+ uint64_t base24_31 : 8;
+ uint64_t base32_63 : 32;
+ uint64_t : 32;
+} __attribute__((packed));
+
+struct tss {
+ uint64_t : 32;
+ uint64_t rsp0 : 64;
+ uint64_t rsp1 : 64;
+ uint64_t rsp2 : 64;
+ uint64_t : 64;
+ uint64_t ist1 : 64;
+ uint64_t ist2 : 64;
+ uint64_t ist3 : 64;
+ uint64_t ist4 : 64;
+ uint64_t ist5 : 64;
+ uint64_t ist6 : 64;
+ uint64_t ist7 : 64;
+ uint64_t : 64;
+ uint64_t : 16;
+ uint64_t iopb : 16;
+} __attribute__((packed));
+
+// tss entry
+static volatile struct tss tss;
+
+// gdt entries
+extern volatile uint8_t GDT[];
+static volatile struct sys_seg_descriptor *GDT_TSS;
+
+// kernel stack pointer
+static char interrupt_stack[PAGE_SIZE * 2];
+
+void tss_init(void)
+{
+ uint64_t base = (uint64_t)&tss;
+ uint64_t limit = sizeof tss - 1;
+
+ // setup tss entry
+ memsetv(&tss, 0, sizeof(struct tss));
+ tss.rsp0 = (uint64_t)interrupt_stack + sizeof(interrupt_stack);
+
+ // map tss into gdt
+ GDT_TSS = (volatile struct sys_seg_descriptor *)(GDT + 0x28);
+ memsetv(GDT_TSS, 0, sizeof(struct sys_seg_descriptor));
+ GDT_TSS->limit0_15 = limit & 0xFFFF;
+ GDT_TSS->base0_15 = base & 0xFFFF;
+ GDT_TSS->base16_23 = (base >> 16) & 0xFF;
+ GDT_TSS->type = 0x9;
+ GDT_TSS->DPL = 0;
+ GDT_TSS->present = 1;
+ GDT_TSS->limit16_19 = (limit >> 16) & 0xF;
+ GDT_TSS->available = 0;
+ GDT_TSS->gran = 0;
+ GDT_TSS->base24_31 = (base >> 24) & 0xFF;
+ GDT_TSS->base32_63 = (base >> 32) & 0xFFFFFFFF;
+
+ tss_flush();
+}
+
+void tss_set_stack(uint64_t stack)
+{
+ tss.rsp0 = stack;
+}
diff --git a/kernel/cpu/tss.h b/kernel/cpu/tss.h
new file mode 100644
index 0000000..f17b619
--- /dev/null
+++ b/kernel/cpu/tss.h
@@ -0,0 +1,31 @@
+/**
+ * @file tss.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * TSS functions
+ */
+
+#ifndef TSS_H_
+#define TSS_H_
+
+#define TSS_REMAP_OFFSET 0x20
+
+#include <stdint.h>
+
+/**
+ * Load the TSS selector
+ */
+void tss_init(void);
+
+/**
+ * Flush the tss
+ */
+void tss_flush(void);
+
+/**
+ * Set the kernel stack pointer in the tss
+ */
+void tss_set_stack(uint64_t stack);
+
+#endif /* tss.h */
diff --git a/kernel/drivers.c b/kernel/drivers.c
index d2230e8..3d6ec10 100644
--- a/kernel/drivers.c
+++ b/kernel/drivers.c
@@ -1,6 +1,7 @@
#include <comus/drivers.h>
#include <comus/drivers/acpi.h>
#include <comus/drivers/uart.h>
+#include <comus/drivers/ps2.h>
#include <comus/drivers/pci.h>
#include <comus/drivers/ata.h>
#include <comus/drivers/gpu.h>
@@ -9,8 +10,9 @@
void drivers_init(void)
{
- pit_set_divider(100); // 1ms
+ pit_set_divider(1193); // 1ms
uart_init();
+ ps2_init();
pci_init();
ata_init();
acpi_init(mboot_get_rsdp());
diff --git a/kernel/drivers/ata.c b/kernel/drivers/ata.c
index 63c4559..6c8de86 100644
--- a/kernel/drivers/ata.c
+++ b/kernel/drivers/ata.c
@@ -506,7 +506,7 @@ static uint8_t get_ata_cmd_for_access(enum lba_mode lba_mode,
static enum ide_error ide_device_ata_access(struct ide_device *dev,
enum access_mode mode, uint32_t lba,
- uint8_t numsects,
+ uint16_t numsects,
uint16_t buf[numsects * 256])
{
struct ide_channel *chan = channel(dev->channel_idx);
@@ -521,7 +521,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
chan->no_interrupt = (ide_irq_invoked = 0x0) + 0x02);
// select one from LBA28, LBA48 or CHS
- if (lba >= 0x10000000) {
+ if (lba >= 0x10000000 || numsects > UINT8_MAX) {
// drive should support LBA in this case, or you are giving a bad LBA
lba_mode = LBA48;
lba_io[0] = (lba & 0x000000FF) >> 0;
@@ -565,19 +565,21 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
if (lba_mode == CHS) {
ide_channel_write(chan, ATA_REG_HDDEVSEL,
0xA0 | (dev->drive_idx << 4) | head);
- } else {
+ } else if (lba_mode == LBA28) {
ide_channel_write(chan, ATA_REG_HDDEVSEL,
0xE0 | (dev->drive_idx << 4) | head);
+ } else {
+ ide_channel_write(chan, ATA_REG_HDDEVSEL, 0x40 | (dev->drive_idx << 4));
}
// write Parameters
- if (lba_mode == 2) {
- ide_channel_write(chan, ATA_REG_SECCOUNT1, 0);
+ if (lba_mode == LBA48) {
+ ide_channel_write(chan, ATA_REG_SECCOUNT1, (numsects >> 8) & 0xff);
ide_channel_write(chan, ATA_REG_LBA3, lba_io[3]);
ide_channel_write(chan, ATA_REG_LBA4, lba_io[4]);
ide_channel_write(chan, ATA_REG_LBA5, lba_io[5]);
}
- ide_channel_write(chan, ATA_REG_SECCOUNT0, numsects);
+ ide_channel_write(chan, ATA_REG_SECCOUNT0, numsects & 0xff);
ide_channel_write(chan, ATA_REG_LBA0, lba_io[0]);
ide_channel_write(chan, ATA_REG_LBA1, lba_io[1]);
ide_channel_write(chan, ATA_REG_LBA2, lba_io[2]);
@@ -624,7 +626,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev,
}
enum ide_error ide_device_read_sectors(ide_device_t dev_identifier,
- uint8_t numsects, uint32_t lba,
+ uint16_t numsects, uint32_t lba,
uint16_t buf[numsects * 256])
{
struct ide_device *dev = device(dev_identifier);
@@ -656,7 +658,7 @@ enum ide_error ide_device_read_sectors(ide_device_t dev_identifier,
}
enum ide_error ide_device_write_sectors(ide_device_t device_identifier,
- uint8_t numsects, uint32_t lba,
+ uint16_t numsects, uint32_t lba,
uint16_t buf[numsects * 256])
{
struct ide_device *dev = device(device_identifier);
diff --git a/kernel/drivers/gpu.c b/kernel/drivers/gpu.c
index 3d79b99..fc6ec8e 100644
--- a/kernel/drivers/gpu.c
+++ b/kernel/drivers/gpu.c
@@ -7,7 +7,7 @@
#include <comus/term.h>
#include <comus/asm.h>
-struct gpu *gpu_dev = NULL;
+struct gpu_dev *gpu_dev = NULL;
int gpu_init(void)
{
diff --git a/kernel/drivers/gpu/bochs.c b/kernel/drivers/gpu/bochs.c
index f8e5820..2dfe62e 100644
--- a/kernel/drivers/gpu/bochs.c
+++ b/kernel/drivers/gpu/bochs.c
@@ -31,7 +31,7 @@
#define BOCHS_HEIGHT 768
#define BOCHS_BIT_DEPTH 32
-struct gpu bochs_dev = { 0 };
+struct gpu_dev bochs_dev = { 0 };
static void write(uint16_t index, uint16_t data)
{
@@ -45,7 +45,7 @@ static uint16_t read(uint16_t value)
return inw(DATA);
}
-int bochs_init(struct gpu **gpu_dev)
+int bochs_init(struct gpu_dev **gpu_dev)
{
struct pci_device bochs = { 0 };
bool found =
diff --git a/kernel/drivers/gpu/gop.c b/kernel/drivers/gpu/gop.c
index 47da952..a57766d 100644
--- a/kernel/drivers/gpu/gop.c
+++ b/kernel/drivers/gpu/gop.c
@@ -5,11 +5,11 @@
#include <comus/efi.h>
#include <efi.h>
-struct gpu gop_dev = { 0 };
+struct gpu_dev gop_dev = { 0 };
static EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
-int gop_init(struct gpu **gpu_dev)
+int gop_init(struct gpu_dev **gpu_dev)
{
gop = efi_get_gop();
if (gop == NULL || gop->Mode == NULL)
diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c
index d77df08..53a9263 100644
--- a/kernel/drivers/pit.c
+++ b/kernel/drivers/pit.c
@@ -22,9 +22,8 @@ uint16_t pit_read_divider(void)
void pit_set_divider(uint16_t count)
{
(void)count;
- // FIXME: broken on -O0
- // cli();
- // outb(CHAN_0, count & 0xFF); // low byte
- // outb(CHAN_0, (count & 0xFF00) >> 8); // high byte
- // sti();
+ cli();
+ outb(CHAN_0, count & 0xFF); // low byte
+ outb(CHAN_0, (count & 0xFF00) >> 8); // high byte
+ sti();
}
diff --git a/kernel/drivers/ps2.c b/kernel/drivers/ps2.c
new file mode 100644
index 0000000..e260f6b
--- /dev/null
+++ b/kernel/drivers/ps2.c
@@ -0,0 +1,268 @@
+#include <comus/drivers/ps2.h>
+#include <comus/keycodes.h>
+#include <comus/input.h>
+#include <comus/asm.h>
+#include <lib.h>
+
+#define STATUS_OUT_BUF ((uint8_t)0x01)
+#define STATUS_IN_BUF ((uint8_t)0x02)
+
+#define CONFIG_INT_0 ((uint8_t)0x01)
+#define CONFIG_INT_1 ((uint8_t)0x02)
+#define CONFIG_SYS ((uint8_t)0x04)
+#define CONFIG_CLOCK_0 ((uint8_t)0x10)
+#define CONFIG_CLOCK_1 ((uint8_t)0x20)
+#define CONFIG_TRANS ((uint8_t)0x40)
+
+static uint8_t scancodes[] = {
+ KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3,
+ KEY_F1, KEY_F2, KEY_F12, KEY_NONE, KEY_F10,
+ KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK,
+ KEY_NONE, KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE,
+ KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W,
+ KEY_2, KEY_NONE, KEY_NONE, KEY_C, KEY_X,
+ KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE,
+ KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T,
+ KEY_R, KEY_5, KEY_NONE, KEY_NONE, KEY_N,
+ KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_M, KEY_J,
+ KEY_U, KEY_7, KEY_8, KEY_NONE, KEY_NONE,
+ KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0,
+ KEY_9, KEY_NONE, KEY_NONE, KEY_PERIOD, KEY_SLASH,
+ KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE,
+ KEY_EQUAL, KEY_NONE, KEY_NONE, KEY_CAPS_LOCK, KEY_R_SHIFT,
+ KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE, KEY_NONE,
+ KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2,
+ KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK,
+ KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK,
+ KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_F7,
+};
+static uint8_t scancodes_ext[] = {
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE,
+ KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_L_META, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_MENU, KEY_UNKNOWN, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+ KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH,
+ KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE,
+ KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_INSERT, KEY_DELETE, KEY_DOWN,
+ KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE,
+ KEY_PAGE_UP, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE,
+ KEY_NONE,
+};
+
+// ctrl
+static bool has_kbd = false;
+static bool has_mouse = false;
+
+// kbd
+static bool state_keyup = false;
+static bool state_ext = false;
+
+// mouse
+static uint8_t first_b, second_b, third_b;
+
+static uint8_t ps2ctrl_in_status(void)
+{
+ return inb(0x64);
+}
+
+static uint8_t ps2ctrl_in(void)
+{
+ while ((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) {
+ io_wait();
+ }
+ return inb(0x60);
+}
+
+static void ps2ctrl_out_cmd(uint8_t cmd)
+{
+ while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x64, cmd);
+}
+
+static void ps2ctrl_out_data(uint8_t data)
+{
+ while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) {
+ io_wait();
+ }
+ outb(0x60, data);
+}
+
+static void ps2ctrl_set_port2(void)
+{
+ outb(0x64, 0xD4);
+}
+
+static int ps2kb_init(void)
+{
+ uint8_t result;
+
+ ps2ctrl_out_data(0xFF);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ if ((result = ps2ctrl_in()) != 0xAA)
+ return 1;
+
+ ps2ctrl_out_data(0xF4);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ has_kbd = true;
+ return 0;
+}
+
+static int ps2mouse_init(void)
+{
+ uint8_t result;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xFF);
+ if ((result = ps2ctrl_in()) != 0xFA)
+ return 1;
+
+ if ((result = ps2ctrl_in()) != 0xAA)
+ return 1;
+
+ ps2ctrl_set_port2();
+ ps2ctrl_out_data(0xF4);
+
+ has_mouse = true;
+ return 0;
+}
+
+void ps2kb_recv(void)
+{
+ static struct keycode keycode;
+ uint8_t code;
+
+ if (!has_kbd)
+ return;
+
+ code = ps2ctrl_in();
+ if (code == 0x00 || code == 0x0F) {
+ keycode.key = KEY_NONE;
+ keycode.flags = KC_FLAG_ERROR;
+ } else if (code == 0xF0) {
+ state_keyup = true;
+ } else if (code == 0xE0) {
+ state_ext = true;
+ } else if (code <= 0x84) {
+ uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes;
+ uint8_t kcode = scancode_table[code];
+ if (kcode != KEY_NONE) {
+ keycode.key = kcode;
+ keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN;
+ keycode_push(&keycode);
+ }
+ state_keyup = false;
+ state_ext = false;
+ }
+}
+
+void ps2mouse_recv(void)
+{
+ static struct mouse_event mouse_ev;
+ static uint8_t packet_num = 0;
+ uint8_t code;
+
+ if (!has_mouse)
+ return;
+
+ code = ps2ctrl_in();
+ switch (packet_num) {
+ case 0:
+ first_b = code;
+ break;
+ case 1:
+ second_b = code;
+ break;
+ case 2: {
+ int state, d;
+
+ third_b = code;
+ state = first_b;
+ d = second_b;
+ mouse_ev.relx = d - ((state << 4) & 0x100);
+ d = third_b;
+ mouse_ev.rely = d - ((state << 3) & 0x100);
+
+ mouse_ev.lmb = first_b & 0x01;
+ mouse_ev.rmb = first_b & 0x02;
+ mouse_ev.mmb = first_b & 0x04;
+ mouse_ev.updated = true;
+ mouse_event_push(&mouse_ev);
+ break;
+ }
+ }
+
+ packet_num += 1;
+ packet_num %= 3;
+}
+
+int ps2_init(void)
+{
+ uint8_t result;
+
+ cli();
+
+ inb(0x60);
+
+ // self-test
+ ps2ctrl_out_cmd(0xAA);
+ if ((result = ps2ctrl_in()) != 0x55) {
+ WARN("PS/2 Controller failed to initalize.");
+ return 1;
+ }
+
+ // set config
+ ps2ctrl_out_cmd(0x20);
+ uint8_t config = ps2ctrl_in();
+ config = (config | CONFIG_INT_0 | CONFIG_INT_1) & ~CONFIG_TRANS;
+ // config = 0xFF;
+ ps2ctrl_out_cmd(0x60);
+ ps2ctrl_out_data(config);
+
+ // enable port 0
+ ps2ctrl_out_cmd(0xAE);
+
+ // enable port 2
+ ps2ctrl_out_cmd(0xA9);
+ if ((result != ps2ctrl_in()) != 0x01) {
+ WARN("PS/2 port 2 not supported");
+ return 1;
+ }
+
+ ps2ctrl_out_cmd(0xA8);
+
+ ps2kb_init();
+ ps2mouse_init();
+ sti();
+ return 0;
+}
diff --git a/kernel/entry.S b/kernel/entry.S
index aa4c38d..4b5415b 100644
--- a/kernel/entry.S
+++ b/kernel/entry.S
@@ -7,8 +7,10 @@
.globl kernel_pd_0_ents
.globl kernel_pd_1
.globl paging_pt
+ .globl GDT
+ .globl kern_stack_end
+ .globl kern_stack_start
.extern main
- .extern GDT
.section .multiboot
@@ -155,6 +157,7 @@ GDT:
# TSS segment (0x28)
.equ GDT.TSS, . - GDT
+ .quad 0
.quad 0 # to be modified in kernel
# GDT Pointer
diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c
index c8399a3..ea47e38 100644
--- a/kernel/fs/fs.c
+++ b/kernel/fs/fs.c
@@ -1,6 +1,7 @@
#include <lib.h>
#include <comus/fs.h>
#include <comus/mboot.h>
+#include <comus/error.h>
struct disk fs_disks[N_DISKS];
struct file_system fs_loaded_file_systems[N_DISKS];
@@ -67,7 +68,7 @@ struct file_system *fs_get_root_file_system(void)
for (int i = 0; i < N_DISKS; i++) {
struct file_system *fs = &fs_loaded_file_systems[i];
- if (fs->present)
+ if (fs->fs_present)
return fs;
}
@@ -97,7 +98,7 @@ static int disk_read_rd(struct disk *disk, size_t offset, size_t len,
{
if (offset + len >= disk->rd.len) {
WARN("attempted to read past length of ramdisk");
- return 1;
+ return -E_BAD_PARAM;
}
memcpy(buffer, disk->rd.start + offset, len);
@@ -110,25 +111,25 @@ static int disk_read_ata(struct disk *disk, size_t offset, size_t len,
static size_t atabuf_len = 0;
static uint16_t *atabuf = NULL;
- uint32_t numsects = (len + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE;
uint32_t err = offset % ATA_SECT_SIZE;
- int ret = 0;
+ uint32_t numsects = (len + err + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE;
+ int ret;
if (atabuf == NULL || atabuf_len < numsects * ATA_SECT_SIZE) {
if ((atabuf = krealloc(atabuf, numsects * ATA_SECT_SIZE)) == NULL)
- return 1;
+ return -E_NO_MEMORY;
atabuf_len = numsects * ATA_SECT_SIZE;
}
// read sectors
if ((ret = ide_device_read_sectors(disk->ide, numsects,
offset / ATA_SECT_SIZE, atabuf)))
- return 1;
+ return ret;
// copy over to buffer
memcpy(buffer, (char *)atabuf + err, len);
- return ret;
+ return len;
}
int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer)
@@ -145,7 +146,7 @@ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer)
default:
ERROR("attempted to read from disk with invalid type: %d\n",
disk->type);
- ret = 1;
+ ret = -E_BAD_PARAM;
}
return ret;
@@ -156,7 +157,7 @@ static int disk_write_rd(struct disk *disk, size_t offset, size_t len,
{
if (offset + len >= disk->rd.len) {
WARN("attempted to write past length of ramdisk");
- return 1;
+ return -E_BAD_PARAM;
}
memcpy(disk->rd.start + offset, buffer, len);
@@ -171,18 +172,18 @@ static int disk_write_ata(struct disk *disk, size_t offset, size_t len,
uint32_t numsects = (len + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE;
uint32_t err = offset % ATA_SECT_SIZE;
- int ret = 0;
+ int ret;
if (atabuf == NULL || atabuf_len < numsects * ATA_SECT_SIZE) {
if ((atabuf = krealloc(atabuf, numsects * ATA_SECT_SIZE)) == NULL)
- return 1;
+ return -E_NO_MEMORY;
atabuf_len = numsects * ATA_SECT_SIZE;
}
// read sectors what will be overwritten
if ((ret = ide_device_read_sectors(disk->ide, numsects,
offset / ATA_SECT_SIZE, atabuf)))
- return 1;
+ return ret;
// copy custom data over
memcpy((char *)atabuf + err, buffer, len);
@@ -190,9 +191,9 @@ static int disk_write_ata(struct disk *disk, size_t offset, size_t len,
// write back sectors
if ((ret = ide_device_write_sectors(disk->ide, numsects,
offset / ATA_SECT_SIZE, atabuf)))
- return 1;
+ return ret;
- return ret;
+ return len;
}
int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer)
@@ -208,7 +209,7 @@ int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer)
break;
default:
ERROR("attempted to write to disk with invalid type: %d\n", disk->type);
- ret = 1;
+ ret = -E_BAD_PARAM;
}
return ret;
diff --git a/kernel/include/comus/asm.h b/kernel/include/comus/asm.h
index c7597e7..4f376b1 100644
--- a/kernel/include/comus/asm.h
+++ b/kernel/include/comus/asm.h
@@ -36,8 +36,10 @@ static inline uint16_t inw(uint16_t port)
static inline void rep_inw(uint16_t port, uint16_t *buffer, size_t count)
{
- while (count--)
- *(buffer++) = inw(port);
+ __asm__ volatile("rep insw"
+ : "+D"(buffer), "+c"(count)
+ : "d"(port)
+ : "memory");
}
static inline void outw(uint16_t port, uint16_t val)
diff --git a/kernel/include/comus/cpu.h b/kernel/include/comus/cpu.h
index ffc1782..df8f44e 100644
--- a/kernel/include/comus/cpu.h
+++ b/kernel/include/comus/cpu.h
@@ -31,6 +31,13 @@ struct cpu_feat {
};
struct cpu_regs {
+ // pgdir
+ uint64_t cr3;
+ // segments
+ uint16_t gs;
+ uint16_t fs;
+ uint16_t es;
+ uint16_t ds;
// registers
uint64_t r15;
uint64_t r14;
@@ -89,4 +96,9 @@ void cpu_feats(struct cpu_feat *feats);
*/
void cpu_print_regs(struct cpu_regs *regs);
+/**
+ * Return from a syscall handler back into userspace
+ */
+__attribute__((noreturn)) void syscall_return(void);
+
#endif /* cpu.h */
diff --git a/kernel/include/comus/drivers/ata.h b/kernel/include/comus/drivers/ata.h
index 2f35e03..c404d84 100644
--- a/kernel/include/comus/drivers/ata.h
+++ b/kernel/include/comus/drivers/ata.h
@@ -44,7 +44,7 @@ enum ide_error ata_init(void);
*
* @returns IDE_ERROR_OK (0) on success or an error code on failure
*/
-enum ide_error ide_device_read_sectors(ide_device_t, uint8_t numsects,
+enum ide_error ide_device_read_sectors(ide_device_t, uint16_t numsects,
uint32_t lba,
uint16_t buf[numsects * 256]);
@@ -53,7 +53,7 @@ enum ide_error ide_device_read_sectors(ide_device_t, uint8_t numsects,
*
* @returns 0 on success or an error code on failure
*/
-enum ide_error ide_device_write_sectors(ide_device_t, uint8_t numsects,
+enum ide_error ide_device_write_sectors(ide_device_t, uint16_t numsects,
uint32_t lba,
uint16_t buf[numsects * 256]);
diff --git a/kernel/include/comus/drivers/gpu.h b/kernel/include/comus/drivers/gpu.h
index 39c633f..0a8f4fa 100644
--- a/kernel/include/comus/drivers/gpu.h
+++ b/kernel/include/comus/drivers/gpu.h
@@ -11,7 +11,7 @@
#include <stdint.h>
-struct gpu {
+struct gpu_dev {
const char *name;
uint16_t width;
uint16_t height;
@@ -31,7 +31,7 @@ struct psf2_font {
uint8_t data[];
};
-extern struct gpu *gpu_dev;
+extern struct gpu_dev *gpu_dev;
extern struct psf2_font en_font;
/**
diff --git a/kernel/include/comus/drivers/gpu/bochs.h b/kernel/include/comus/drivers/gpu/bochs.h
index 7d26b60..ec70060 100644
--- a/kernel/include/comus/drivers/gpu/bochs.h
+++ b/kernel/include/comus/drivers/gpu/bochs.h
@@ -15,6 +15,6 @@
* Loads the bochs graphics driver
* @returns 0 on success, NULL on error
*/
-int bochs_init(struct gpu **gpu_dev);
+int bochs_init(struct gpu_dev **gpu_dev);
#endif /* bochs.h */
diff --git a/kernel/include/comus/drivers/gpu/gop.h b/kernel/include/comus/drivers/gpu/gop.h
index 6475f05..d3af921 100644
--- a/kernel/include/comus/drivers/gpu/gop.h
+++ b/kernel/include/comus/drivers/gpu/gop.h
@@ -15,6 +15,6 @@
* Loads the uefi gop graphics driver
* @returns 0 on success, NULL on error
*/
-int gop_init(struct gpu **gpu_dev);
+int gop_init(struct gpu_dev **gpu_dev);
#endif /* gop.h */
diff --git a/kernel/include/comus/drivers/ps2.h b/kernel/include/comus/drivers/ps2.h
new file mode 100644
index 0000000..7634e5f
--- /dev/null
+++ b/kernel/include/comus/drivers/ps2.h
@@ -0,0 +1,27 @@
+/**
+ * @file ps2.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * PS/2 Mouse & Keyboard
+ */
+
+#ifndef PS2_H_
+#define PS2_H_
+
+/**
+ * Initalize the ps2 controller
+ */
+int ps2_init(void);
+
+/**
+ * Recieve input from ps2 keyboard during interrupt
+ */
+void ps2kb_recv(void);
+
+/**
+ * Recieve input from ps2 mouse during interrupt
+ */
+void ps2mouse_recv(void);
+
+#endif /* ps2.h */
diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h
index e67b6fe..c48e3e1 100644
--- a/kernel/include/comus/fs.h
+++ b/kernel/include/comus/fs.h
@@ -9,7 +9,6 @@
#ifndef FS_H_
#define FS_H_
-#include <stdint.h>
#include <stddef.h>
#include <comus/limits.h>
#include <comus/drivers/ata.h>
@@ -45,7 +44,7 @@ struct disk {
* @param offset - the offset into the disk to read
* @param len - the length of the data to read into `buffer`
* @param buffer - the buffer to save data into
- * @returns bytes read on success, negative fs error code in failure
+ * @returns number of bytes read on success, negative fs error code in failure
*/
int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer);
@@ -56,7 +55,7 @@ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer);
* @param offset - the offset into the disk to write
* @param len - the length of the data to write into `buffer`
* @param buffer - the buffer to read from
- * @returns bytes written on success, negative fs error code in failure
+ * @returns number of bytes written on success, negative fs error code in failure
*/
int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer);
@@ -65,104 +64,55 @@ enum file_type {
F_REG = 0,
// directory
F_DIR = 1,
- // symbolic link
- F_SYM = 2,
};
-/// TODO: file name queue or storage area???
-/// hash map?!? (performance !!! :) )
+struct dirent {
+ int d_id;
+ unsigned long d_offset;
+ unsigned short d_namelen;
+ char d_name[N_FILE_NAME];
+};
+
+struct stat {
+ /// file id
+ int s_id;
+ /// file type
+ enum file_type s_type;
+ /// file length
+ unsigned long s_length;
+};
struct file {
- /// name of the file
- char name[N_FILE_NAME];
- /// parent directory of the file
- struct file_s *parent;
- /// type of the file
- enum file_type type;
- /// the filesystem of this file
- struct file_system *fsys;
+ /// file id
+ int f_id;
+ /// read from the file
+ int (*read)(struct file *, char *, size_t);
+ /// write into the file
+ int (*write)(struct file *, char *, size_t);
+ /// seeks the file
+ int (*seek)(struct file *, long);
+ /// get directory entry at index
+ int (*ents)(struct file *, struct dirent *, size_t);
};
-/// vtable for filesystem functions
-/// NOTE: feel free to change this as needed
-/// its just stuff that i thought may be good
struct file_system {
/// set to 1 in fs array to state that fs is defined
/// system use only
- int present;
+ int fs_present;
/// index into the loaded filesystems array
/// system use only
- int id;
+ int fs_id;
+ /// mount point of this filesystem
+ /// system use only
+ char fs_mount[N_FILE_NAME];
/// the disk this filesystem is hooked up to
struct disk disk;
- /// get root file in file file_system
- /// @param fs - the file system
- /// @returns the root file or NULL on failure
- struct file *(*fs_get_root_file)(struct file_system *fs);
- /// rename a file
- /// @param fs - the file system
- /// @param file - the file to rename
- /// @param name - the new file name
- /// @returns 0 on success, or an negative fs error code on failure
- int (*fs_rename_file)(struct file_system *fs, struct file *file,
- char *name);
- /// get length of file
- /// @param fs - the file system
- /// @param file - the file to get the length of
- /// @param length - the pointer to save the length to
- /// @return 0 on success, or an negative fs error code on failure
- int (*fs_get_file_length)(struct file_system *fs, struct file *file,
- uint64_t *length);
- /// get created date of file
- /// @param fs - the file system
- /// @param file - the file to get the date created
- /// @param created - the pointer to save the created date to
- /// @param modified - the pointer to save the modified date to
- /// @param accessed - the pointer to save the accessed date to
- /// @return 0 on success, or an negative fs error code on failure
- int (*fs_get_file_dates)(struct file_system *fs, struct file *file,
- uint64_t *created, uint64_t *modified,
- uint64_t *accessed);
- /// delete a file in the file system
- /// @param fs - the file system
- /// @param file - the file to delete
- /// @returns 0 on success, or an negative fs error code on failure
- int (*fs_delete_file)(struct file_system *fs, struct file *file);
- /// create a file with a given name and type
- /// @param fs - the file system
- /// @param res - the new file structure to save the new file into
- /// @param parent - the parent (directory) of the file to create
- /// @param type - the type of file to create
- /// @returns 0 on success, or an negative fs error code on failure
- int (*fs_new_file)(struct file_system *fs, struct file *res,
- struct file *parent, enum file_type type);
- /// get files in a directory
- /// @param fs - the file system
- /// @param dir - the directory to search into
- /// @param start - the directory entry to start at
- /// @param len - the max number of entrys to save starting at `start`
- /// @param res - the list of structures to save into
- /// @returns number of entries read, or an negative fs error code on failure
- int (*fs_get_dir_ents)(struct file_system *fs, struct file *dir,
- size_t start, size_t len, struct file res[]);
- /// read from a file
- /// @param fs - the file system
- /// @param file - the file to read from
- /// @param offset - the offset of the file to read into
- /// @param length - the length of the file to read starting at `offset`
- /// @param buffer - the buffer to save the data into
- /// @returns number of bytes read, or an negative fs error code on failure
- int (*fs_read_file)(struct file_system *fs, struct file *file,
- size_t offset, size_t length, uint8_t *buffer);
- /// write into a file
- /// @param fs - the file system
- /// @param file - the file to write to
- /// @param offset - the offset of the file to write into
- /// @param length - the length of the data to write
- /// @param buffer - the buffer the data to write is stored in
- /// @returns number of bytes written, or an negative fs error code on failure
- int (*fs_write_file)(struct file_system *fs, struct file *file,
- size_t offset, size_t length, uint8_t *buffer);
+ /// opens a file
+ int (*open)(const char *, struct file **);
+ /// closes a file
+ void (*close)(struct file *);
+ /// stats a file
+ int (*stat)(const char *, struct stat *);
};
// list of all disks on the system
@@ -190,29 +140,4 @@ struct disk *fs_get_root_disk(void);
*/
struct file_system *fs_get_root_file_system(void);
-/**
- * Find a file in the given file system, traversing the path
- * Always use this function to find files globally
- *
- * @param fs - the file system to search
- * @param name - the absolute path of the file to look for
- * @param res - where to store the file structure
- * @returns 0 on success, or an negative fs error code on failure
- */
-int fs_find_file_abs(struct file_system *fs, char *abs_path, struct file *res);
-
-/**
- * Find a file in the given file system, traversing the path, relative to
- * another file.
- * Always use this function to find files globally
- *
- * @param rel - the relative file to search from
- * @param name - the absolute path of the file to look for
- * @param res - where to store the file structure
- * @returns 0 on success, or an negative fs error code on failure
- */
-int fs_find_file_rel(struct file *rel, char *rel_path, struct file *res);
-
-// NOTE: fell free to add more functions if needed :)
-
#endif /* fs.h */
diff --git a/kernel/include/comus/input.h b/kernel/include/comus/input.h
new file mode 100644
index 0000000..b2b3053
--- /dev/null
+++ b/kernel/include/comus/input.h
@@ -0,0 +1,36 @@
+/**
+ * @file input.h
+ */
+
+#ifndef INPUT_H_
+#define INPUT_H_
+
+#include <comus/keycodes.h>
+#include <comus/limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+struct keycode {
+ char key;
+ char flags;
+};
+
+struct mouse_event {
+ bool updated;
+ bool lmb;
+ bool rmb;
+ bool mmb;
+ int relx;
+ int rely;
+};
+
+void keycode_push(struct keycode *ev);
+int keycode_pop(struct keycode *ev);
+size_t keycode_len(void);
+char keycode_to_char(struct keycode *ev);
+
+void mouse_event_push(struct mouse_event *ev);
+int mouse_event_pop(struct mouse_event *ev);
+size_t mouse_event_len(void);
+
+#endif /* input.h */
diff --git a/kernel/include/comus/keycodes.h b/kernel/include/comus/keycodes.h
new file mode 100644
index 0000000..ebf296a
--- /dev/null
+++ b/kernel/include/comus/keycodes.h
@@ -0,0 +1,138 @@
+/**
+ * @file keycodes.h
+ *
+ * @author Tristan Miller <trimill@trimill.xyz>
+ *
+ * Kernel keycodes
+ */
+
+#ifndef KEYCODES_H_
+#define KEYCODES_H_
+
+#define KC_FLAG_KEY_DOWN 0x01
+#define KC_FLAG_KEY_UP 0x02
+#define KC_FLAG_ERROR 0x04
+
+#define KEY_NONE 0x00
+#define KEY_UNKNOWN 0x01
+
+#define KEY_ESCAPE 0x10
+#define KEY_1 0x11
+#define KEY_2 0x12
+#define KEY_3 0x13
+#define KEY_4 0x14
+#define KEY_5 0x15
+#define KEY_6 0x16
+#define KEY_7 0x17
+#define KEY_8 0x18
+#define KEY_9 0x19
+#define KEY_0 0x1A
+#define KEY_MINUS 0x1B
+#define KEY_EQUAL 0x1C
+#define KEY_BACKSPACE 0x1D
+#define KEY_L_SHIFT 0x1E
+#define KEY_R_SHIFT 0x1F
+
+#define KEY_TAB 0x20
+#define KEY_Q 0x21
+#define KEY_W 0x22
+#define KEY_E 0x23
+#define KEY_R 0x24
+#define KEY_T 0x25
+#define KEY_Y 0x26
+#define KEY_U 0x27
+#define KEY_I 0x28
+#define KEY_O 0x29
+#define KEY_P 0x2A
+#define KEY_L_BRACE 0x2B
+#define KEY_R_BRACE 0x2C
+#define KEY_BACKSLASH 0x2D
+#define KEY_L_CTRL 0x2E
+#define KEY_R_CTRL 0x2F
+
+#define KEY_CAPS_LOCK 0x30
+#define KEY_A 0x31
+#define KEY_S 0x32
+#define KEY_D 0x33
+#define KEY_F 0x34
+#define KEY_G 0x35
+#define KEY_H 0x36
+#define KEY_J 0x37
+#define KEY_K 0x38
+#define KEY_L 0x39
+#define KEY_SEMICOLON 0x3A
+#define KEY_QUOTE 0x3B
+#define KEY_ENTER 0x3C
+#define KEY_MENU 0x3D
+#define KEY_L_ALT 0x3E
+#define KEY_R_ALT 0x3F
+
+#define KEY_SPACE 0x40
+#define KEY_Z 0x41
+#define KEY_X 0x42
+#define KEY_C 0x43
+#define KEY_V 0x44
+#define KEY_B 0x45
+#define KEY_N 0x46
+#define KEY_M 0x47
+#define KEY_COMMA 0x48
+#define KEY_PERIOD 0x49
+#define KEY_SLASH 0x4A
+#define KEY_BACKTICK 0x4B
+#define KEY_NUM_LOCK 0x4C
+#define KEY_SCROLL_LOCK 0x4D
+#define KEY_L_META 0x4E
+#define KEY_R_META 0x4F
+
+#define KEY_NP_SLASH 0x50
+#define KEY_NP_7 0x51
+#define KEY_NP_8 0x52
+#define KEY_NP_9 0x53
+#define KEY_NP_ASTERISK 0x54
+#define KEY_NP_4 0x55
+#define KEY_NP_5 0x56
+#define KEY_NP_6 0x57
+#define KEY_NP_MINUS 0x58
+#define KEY_NP_1 0x59
+#define KEY_NP_2 0x5A
+#define KEY_NP_3 0x5B
+#define KEY_NP_PLUS 0x5C
+#define KEY_NP_0 0x5D
+#define KEY_NP_PERIOD 0x5E
+#define KEY_NP_ENTER 0x5F
+
+#define KEY_PRINT_SCREEN 0x60
+#define KEY_PAUSE 0x61
+#define KEY_INSERT 0x62
+#define KEY_HOME 0x63
+#define KEY_PAGE_UP 0x64
+#define KEY_DELETE 0x65
+#define KEY_END 0x66
+#define KEY_PAGE_DOWN 0x67
+#define KEY_UP 0x68
+#define KEY_DOWN 0x69
+#define KEY_LEFT 0x6A
+#define KEY_RIGHT 0x6B
+// #define _ 0x6C
+// #define _ 0x6D
+// #define _ 0x6E
+// #define _ 0x6F
+
+#define KEY_F1 0x70
+#define KEY_F2 0x71
+#define KEY_F3 0x72
+#define KEY_F4 0x73
+#define KEY_F5 0x74
+#define KEY_F6 0x75
+#define KEY_F7 0x76
+#define KEY_F8 0x77
+#define KEY_F9 0x78
+#define KEY_F10 0x79
+#define KEY_F11 0x7A
+#define KEY_F12 0x7B
+// #define _ 0x7C
+// #define _ 0x7D
+// #define _ 0x7E
+// #define _ 0x7F
+
+#endif /* keycodes */
diff --git a/kernel/include/comus/limits.h b/kernel/include/comus/limits.h
index 675df47..4cb348d 100644
--- a/kernel/include/comus/limits.h
+++ b/kernel/include/comus/limits.h
@@ -20,8 +20,16 @@
/// max fs limits
#define N_FILE_NAME 256
+#define N_DIR_ENTS 256
#define N_DISKS 8
+/// elf limits
+#define N_ELF_SEGMENTS 16
+
+/// input buffer
+#define N_KEYCODE 64
+#define N_MOUSEEV 64
+
/// length of terminal buffer
#define TERM_MAX_WIDTH 1920
#define TERM_MAX_HEIGHT 1080
diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h
index 942e7a8..47ea103 100644
--- a/kernel/include/comus/memory.h
+++ b/kernel/include/comus/memory.h
@@ -87,7 +87,7 @@ mem_ctx_t mem_ctx_alloc(void);
*
* @returns pointer context or NULL on failure
*/
-mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow);
+mem_ctx_t mem_ctx_clone(const mem_ctx_t ctx, bool cow);
/**
* Free a memory context into a new one
@@ -104,6 +104,11 @@ void mem_ctx_free(mem_ctx_t ctx);
void mem_ctx_switch(mem_ctx_t ctx);
/**
+ * @returns the pgdir pointer in the memory ctx
+ */
+volatile void *mem_ctx_pgdir(mem_ctx_t ctx);
+
+/**
* Allocates at least len bytes of memory starting at
* physical address addr. Returned address can be
* any virtural address.
@@ -121,7 +126,14 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len,
* Unmaps mapped address from the kmapaddr function
* @param virt - the vitural address returned from kmapaddr
*/
-void mem_unmapaddr(mem_ctx_t ctx, void *virt);
+void mem_unmapaddr(mem_ctx_t ctx, const void *virt);
+
+/**
+ * Gets the physical address for a given vitural address
+ * @param ctx - the memory context
+ * @param virt - the vitural address
+ */
+void *mem_get_phys(mem_ctx_t ctx, const void *virt);
/**
* Allocate a single page of memory with the given paging structure
@@ -169,7 +181,7 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt,
*
* @param ptr - the pointer provided by alloc_page or alloc_pages
*/
-void mem_free_pages(mem_ctx_t ctx, void *ptr);
+void mem_free_pages(mem_ctx_t ctx, const void *ptr);
/**
* Allocates at least len bytes of memory starting at
@@ -185,10 +197,26 @@ void mem_free_pages(mem_ctx_t ctx, void *ptr);
void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags);
/**
+ * Map a vitural address in a userspace context to kernel space
+ *
+ * @param ctx - the userspace memory context to map from
+ * @param virt - the vitural address given by userspace
+ * @param len - the length of the buffer to map
+ * @returns vitural address mapped in kernel context
+ */
+void *kmapuseraddr(mem_ctx_t ctx, const void *virt, size_t len);
+
+/**
+ * Gets the physical address for a given vitural address
+ * @param virt - the vitural address
+ */
+void *kget_phys(const void *virt);
+
+/**
* Unmaps mapped address from the kmapaddr function
* @param virt - the vitural address returned from kmapaddr
*/
-void kunmapaddr(void *virt);
+void kunmapaddr(const void *virt);
/**
* Allocate a single page of memory
@@ -210,6 +238,6 @@ void *kalloc_pages(size_t count);
*
* @param ptr - the pointer provided by alloc_page or alloc_pages
*/
-void kfree_pages(void *ptr);
+void kfree_pages(const void *ptr);
#endif /* memory.h */
diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h
index d92bc5d..7b1a70a 100644
--- a/kernel/include/comus/procs.h
+++ b/kernel/include/comus/procs.h
@@ -12,10 +12,12 @@
#include <comus/cpu.h>
#include <comus/limits.h>
#include <comus/memory.h>
+#include <comus/syscalls.h>
#include <lib.h>
+#include <elf.h>
-#define PCB_REG(pcb, x) ((pcb)->regs->x)
-#define PCB_RET(pcb) ((pcb)->regs->rax)
+#define PCB_REG(pcb, x) ((pcb)->regs.x)
+#define PCB_RET(pcb) ((pcb)->regs.rax)
#define PCB_ARG1(pcb) PCB_REG((pcb), rdi)
#define PCB_ARG2(pcb) PCB_REG((pcb), rsi)
#define PCB_ARG3(pcb) PCB_REG((pcb), rdx)
@@ -33,11 +35,8 @@ enum proc_state {
PROC_STATE_READY,
PROC_STATE_RUNNING,
// runnable, but waiting for some event
- PROC_STATE_SLEEPING,
PROC_STATE_BLOCKED,
- PROC_STATE_WAITING,
// no longer runnalbe
- PROC_STATE_KILLED,
PROC_STATE_ZOMBIE,
// sentinel
N_PROC_STATES,
@@ -46,8 +45,8 @@ enum proc_state {
/// process control block
struct pcb {
// context
- struct cpu_regs *regs;
mem_ctx_t memctx;
+ struct cpu_regs regs;
// metadata
pid_t pid;
@@ -56,10 +55,20 @@ struct pcb {
size_t priority;
size_t ticks;
+ // heap
+ char *heap_start;
+ size_t heap_len;
+
+ // elf metadata
+ Elf64_Ehdr elf_header;
+ Elf64_Phdr elf_segments[N_ELF_SEGMENTS];
+ Elf64_Half n_elf_segments;
+
// queue linkage
struct pcb *next; // next PDB in queue
// process state information
+ uint64_t syscall;
uint64_t wakeup;
uint8_t exit_status;
};
@@ -79,10 +88,9 @@ typedef struct pcb_queue_s *pcb_queue_t;
/// public facing pcb queues
extern pcb_queue_t pcb_freelist;
-extern pcb_queue_t ready;
-extern pcb_queue_t waiting;
-extern pcb_queue_t sleeping;
-extern pcb_queue_t zombie;
+extern pcb_queue_t ready_queue;
+extern pcb_queue_t zombie_queue;
+extern pcb_queue_t syscall_queue[N_SYSCALLS];
/// pointer to the currently-running process
extern struct pcb *current_pcb;
@@ -216,6 +224,11 @@ void schedule(struct pcb *pcb);
/**
* Select the next process to receive the CPU
*/
-void dispatch(void);
+__attribute__((noreturn)) void dispatch(void);
+
+/**
+ * Scheduler function called on every system tick
+ */
+void pcb_on_tick(void);
#endif /* procs.h */
diff --git a/kernel/include/comus/syscalls.h b/kernel/include/comus/syscalls.h
index 3dc128d..f714184 100644
--- a/kernel/include/comus/syscalls.h
+++ b/kernel/include/comus/syscalls.h
@@ -27,9 +27,12 @@
#define SYS_sleep 14
#define SYS_brk 15
#define SYS_sbrk 16
+#define SYS_poweroff 17
+#define SYS_drm 18
+#define SYS_ticks 19
// UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED!
-#define N_SYSCALLS 13
+#define N_SYSCALLS 20
// interrupt vector entry for system calls
#define VEC_SYSCALL 0x80
diff --git a/kernel/include/comus/user.h b/kernel/include/comus/user.h
new file mode 100644
index 0000000..f51ada5
--- /dev/null
+++ b/kernel/include/comus/user.h
@@ -0,0 +1,30 @@
+/**
+ * @file user.h
+ *
+ * @author Freya Murphy <freya@freyacat.org>
+ *
+ * Userland functions
+ */
+
+#ifndef USER_H_
+#define USER_H_
+
+#include <comus/procs.h>
+#include <comus/fs.h>
+
+/**
+ * Load a user elf program from a file into a pcb
+ */
+int user_load(struct pcb *pcb, struct disk *disk);
+
+/**
+ * Clone a user process. Used for fork().
+ */
+struct pcb *user_clone(struct pcb *pcb);
+
+/**
+ * Clean up all loaded userland data from a pcb
+ */
+void user_cleanup(struct pcb *pcb);
+
+#endif /* user.h */
diff --git a/kernel/include/lib.h b/kernel/include/lib.h
index be4e739..edfbeb4 100644
--- a/kernel/include/lib.h
+++ b/kernel/include/lib.h
@@ -15,6 +15,7 @@
#include <lib/kctype.h>
#include <lib/kio.h>
#include <lib/klib.h>
+#include <lib/kmath.h>
#include <lib/kstring.h>
#endif /* lib.h */
diff --git a/kernel/include/lib/kmath.h b/kernel/include/lib/kmath.h
new file mode 100644
index 0000000..3be953d
--- /dev/null
+++ b/kernel/include/lib/kmath.h
@@ -0,0 +1,20 @@
+/**
+ * @file kmath.h
+ *
+ * @author Ian McFarlane <i.mcfarlane2002@gmail.com>
+ *
+ * Kernel math functions
+ */
+
+#ifndef _KMATH_H
+#define _KMATH_H
+
+#include <stddef.h>
+
+// min and max both prefer a over b
+#define MAX(a, b) ((a) >= (b) ? (a) : (b))
+#define MIN(a, b) ((a) <= (b) ? (a) : (b))
+
+#define CLAMP(val, min, max) (MAX((min), MIN((val), (max))))
+
+#endif
diff --git a/kernel/input.c b/kernel/input.c
new file mode 100644
index 0000000..2073950
--- /dev/null
+++ b/kernel/input.c
@@ -0,0 +1,93 @@
+#include <comus/input.h>
+
+struct mouse_event_buf {
+ struct mouse_event data[N_MOUSEEV];
+ size_t start;
+ size_t end;
+ size_t len;
+};
+
+struct keycode_buf {
+ struct keycode data[N_KEYCODE];
+ size_t start;
+ size_t end;
+ size_t len;
+};
+
+static struct keycode_buf keycode_buffer = {
+ .start = 0,
+ .end = 0,
+ .len = 0,
+};
+
+static struct mouse_event_buf mouse_event_buffer = {
+ .start = 0,
+ .end = 0,
+ .len = 0,
+};
+
+void keycode_push(struct keycode *ev)
+{
+ // save keycode
+ keycode_buffer.data[keycode_buffer.end] = *ev;
+
+ // update pointers
+ keycode_buffer.end++;
+ keycode_buffer.end %= N_KEYCODE;
+ if (keycode_buffer.len < N_KEYCODE) {
+ keycode_buffer.len++;
+ } else {
+ keycode_buffer.start++;
+ keycode_buffer.start %= N_KEYCODE;
+ }
+}
+
+int keycode_pop(struct keycode *ev)
+{
+ if (keycode_buffer.len < 1)
+ return 1;
+
+ *ev = keycode_buffer.data[keycode_buffer.start];
+ keycode_buffer.len--;
+ keycode_buffer.start++;
+ keycode_buffer.start %= N_KEYCODE;
+ return 0;
+}
+
+size_t keycode_len(void)
+{
+ return keycode_buffer.len;
+}
+
+void mouse_event_push(struct mouse_event *ev)
+{
+ // save mouse_event
+ mouse_event_buffer.data[mouse_event_buffer.end] = *ev;
+
+ // update pointers
+ mouse_event_buffer.end++;
+ mouse_event_buffer.end %= N_KEYCODE;
+ if (mouse_event_buffer.len < N_KEYCODE) {
+ mouse_event_buffer.len++;
+ } else {
+ mouse_event_buffer.start++;
+ mouse_event_buffer.start %= N_KEYCODE;
+ }
+}
+
+int mouse_event_pop(struct mouse_event *ev)
+{
+ if (mouse_event_buffer.len < 1)
+ return 1;
+
+ *ev = mouse_event_buffer.data[mouse_event_buffer.start];
+ mouse_event_buffer.len--;
+ mouse_event_buffer.start++;
+ mouse_event_buffer.start %= N_KEYCODE;
+ return 0;
+}
+
+size_t mouse_event_len(void)
+{
+ return mouse_event_buffer.len;
+}
diff --git a/kernel/lib/backtrace.c b/kernel/lib/backtrace.c
index 485cc0f..2507be4 100644
--- a/kernel/lib/backtrace.c
+++ b/kernel/lib/backtrace.c
@@ -6,6 +6,13 @@ struct stackframe {
void *rip;
};
+extern char kern_stack_start[];
+extern char kern_stack_end[];
+
+#define VALID(frame) \
+ (frame && (char *)(frame) >= kern_stack_start && \
+ ((char *)(frame) <= kern_stack_end))
+
size_t backtrace(void **dst, size_t len)
{
struct stackframe *rbp;
@@ -17,11 +24,13 @@ size_t backtrace_ex(void **dst, size_t len, void *ip, void *bp)
{
struct stackframe *frame = bp;
__asm__("mov %%rbp, %0" : "=r"(frame));
+ if (!VALID(frame))
+ return 0;
if (len > 0) {
dst[0] = ip;
}
size_t i;
- for (i = 1; frame && i < len; i++) {
+ for (i = 1; VALID(frame) && i < len; i++) {
dst[i] = frame->rip;
frame = frame->rbp;
}
@@ -38,9 +47,11 @@ void log_backtrace(void)
void log_backtrace_ex(void *ip, void *bp)
{
struct stackframe *frame = bp;
+ if (!VALID(frame))
+ return;
kputs("Stack trace:\n");
kprintf(" %p\t%s\n", ip, mboot_get_elf_sym((uint64_t)ip));
- while (frame) {
+ while (VALID(frame)) {
kprintf(" %p\t%s\n", frame->rip,
mboot_get_elf_sym((uint64_t)frame->rip));
frame = frame->rbp;
diff --git a/kernel/lib/kalloc.c b/kernel/lib/kalloc.c
index 9845a62..0141149 100644
--- a/kernel/lib/kalloc.c
+++ b/kernel/lib/kalloc.c
@@ -54,7 +54,8 @@ static void *alloc_new(size_t size)
}
struct page_header *header = addr;
- header->magic = 0xBEEFCAFE;
+ memsetv(header, 0, sizeof(struct page_header));
+ header->magic = MAGIC;
header->used = size;
header->free = free;
header->prev = end_header;
diff --git a/kernel/lib/memcmp.c b/kernel/lib/memcmp.c
index f938d0a..464fda3 100644
--- a/kernel/lib/memcmp.c
+++ b/kernel/lib/memcmp.c
@@ -1,6 +1,6 @@
#include <lib.h>
-int memcmp(const void *restrict vl, const void *restrict vr, size_t n)
+int memcmp(const void *restrict vl, const void *restrict vr, register size_t n)
{
const unsigned char *l = vl, *r = vr;
for (; n && *l == *r; n--, l++, r++)
diff --git a/kernel/lib/memcpy.c b/kernel/lib/memcpy.c
index e848cef..168c926 100644
--- a/kernel/lib/memcpy.c
+++ b/kernel/lib/memcpy.c
@@ -1,6 +1,6 @@
#include <lib.h>
-void *memcpy(void *restrict dest, const void *restrict src, size_t n)
+void *memcpy(void *restrict dest, const void *restrict src, register size_t n)
{
char *d = dest;
const char *s = src;
diff --git a/kernel/lib/memmove.c b/kernel/lib/memmove.c
index 55be66d..b413c1f 100644
--- a/kernel/lib/memmove.c
+++ b/kernel/lib/memmove.c
@@ -1,6 +1,6 @@
#include <lib.h>
-void *memmove(void *dest, const void *src, size_t n)
+void *memmove(void *dest, const void *src, register size_t n)
{
char *d = dest;
const char *s = src;
diff --git a/kernel/lib/memmovev.c b/kernel/lib/memmovev.c
index 56684a5..7884cef 100644
--- a/kernel/lib/memmovev.c
+++ b/kernel/lib/memmovev.c
@@ -1,6 +1,7 @@
#include <lib.h>
-volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n)
+volatile void *memmovev(volatile void *dest, const volatile void *src,
+ register size_t n)
{
volatile char *d = dest;
volatile const char *s = src;
diff --git a/kernel/lib/memset.c b/kernel/lib/memset.c
index d1c2a5e..7132e02 100644
--- a/kernel/lib/memset.c
+++ b/kernel/lib/memset.c
@@ -1,6 +1,6 @@
#include <lib.h>
-void *memset(void *dest, int c, size_t n)
+void *memset(void *dest, int c, register size_t n)
{
unsigned char *d = dest;
for (; n; n--) {
diff --git a/kernel/lib/memsetv.c b/kernel/lib/memsetv.c
index 647847f..d5267b7 100644
--- a/kernel/lib/memsetv.c
+++ b/kernel/lib/memsetv.c
@@ -1,6 +1,6 @@
#include <lib.h>
-volatile void *memsetv(volatile void *dest, int c, size_t n)
+volatile void *memsetv(volatile void *dest, int c, register size_t n)
{
volatile unsigned char *d = dest;
for (; n; n--) {
diff --git a/kernel/main.c b/kernel/main.c
index 4047a64..c15c38d 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -7,6 +7,7 @@
#include <comus/drivers/pci.h>
#include <comus/drivers/gpu.h>
#include <comus/drivers/ata.h>
+#include <comus/user.h>
#include <comus/fs.h>
#include <comus/procs.h>
#include <lib.h>
@@ -21,7 +22,7 @@ void kreport(void)
gpu_report();
}
-void main(long magic, volatile void *mboot)
+__attribute__((noreturn)) void main(long magic, volatile void *mboot)
{
// initalize idt and pic
cpu_init();
@@ -47,6 +48,12 @@ void main(long magic, volatile void *mboot)
// report system state
kreport();
- // halt
- kprintf("halting...\n");
+ // load init process
+ pcb_alloc(&init_pcb);
+ if (user_load(init_pcb, &fs_disks[0]))
+ panic("failed to load init");
+
+ // schedule and dispatch init
+ schedule(init_pcb);
+ dispatch();
}
diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c
index 2a9c15e..ecfd639 100644
--- a/kernel/memory/memory.c
+++ b/kernel/memory/memory.c
@@ -26,11 +26,16 @@ void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags)
return mem_mapaddr(kernel_mem_ctx, phys, virt, len, flags);
}
-void kunmapaddr(void *virt)
+void kunmapaddr(const void *virt)
{
mem_unmapaddr(kernel_mem_ctx, virt);
}
+void *kget_phys(const void *virt)
+{
+ return mem_get_phys(kernel_mem_ctx, virt);
+}
+
void *kalloc_page(void)
{
return mem_alloc_page(kernel_mem_ctx, F_PRESENT | F_WRITEABLE);
@@ -41,7 +46,7 @@ void *kalloc_pages(size_t count)
return mem_alloc_pages(kernel_mem_ctx, count, F_PRESENT | F_WRITEABLE);
}
-void kfree_pages(void *ptr)
+void kfree_pages(const void *ptr)
{
mem_free_pages(kernel_mem_ctx, ptr);
}
@@ -52,7 +57,7 @@ mem_ctx_t mem_ctx_alloc(void)
if (ctx == NULL)
return NULL;
- if ((ctx->pml4 = paging_alloc()) == NULL)
+ if ((ctx->pml4 = pgdir_alloc()) == NULL)
return NULL;
virtaddr_init(&ctx->virtctx);
@@ -64,17 +69,39 @@ mem_ctx_t mem_ctx_alloc(void)
return ctx;
}
-mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow)
+mem_ctx_t mem_ctx_clone(const mem_ctx_t old, bool cow)
{
- (void)ctx;
- (void)cow;
+ mem_ctx_t new;
+
+ assert(old != NULL, "memory context is null");
+ assert(old->pml4 != NULL, "pgdir is null");
+
+ new = user_mem_ctx_next;
+ if (new == NULL)
+ return NULL;
+
+ if ((new->pml4 = pgdir_clone(old->pml4, cow)) == NULL)
+ return NULL;
+
+ if (virtaddr_clone(&old->virtctx, &new->virtctx)) {
+ pgdir_free(new->pml4);
+ return NULL;
+ }
+
+ user_mem_ctx_next = new->prev;
+ if (new->prev)
+ new->prev->next = NULL;
+ new->prev = NULL;
- panic("not yet implemented");
+ return new;
}
void mem_ctx_free(mem_ctx_t ctx)
{
- paging_free(ctx->pml4);
+ assert(ctx != NULL, "memory context is null");
+ assert(ctx->pml4 != NULL, "pgdir is null");
+
+ pgdir_free(ctx->pml4);
virtaddr_cleanup(&ctx->virtctx);
if (user_mem_ctx_next == NULL) {
@@ -88,9 +115,20 @@ void mem_ctx_free(mem_ctx_t ctx)
void mem_ctx_switch(mem_ctx_t ctx)
{
+ assert(ctx != NULL, "memory context is null");
+ assert(ctx->pml4 != NULL, "pgdir is null");
+
__asm__ volatile("mov %0, %%cr3" ::"r"(ctx->pml4) : "memory");
}
+volatile void *mem_ctx_pgdir(mem_ctx_t ctx)
+{
+ assert(ctx != NULL, "memory context is null");
+ assert(ctx->pml4 != NULL, "pgdir is null");
+
+ return ctx->pml4;
+}
+
void memory_init(void)
{
struct memory_map mmap;
diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c
index 4f1b788..763bdce 100644
--- a/kernel/memory/paging.c
+++ b/kernel/memory/paging.c
@@ -5,6 +5,7 @@
#include "physalloc.h"
#include "paging.h"
#include "memory.h"
+#include <stdint.h>
// PAGE MAP LEVEL 4 ENTRY
struct pml4e {
@@ -138,83 +139,55 @@ extern char kernel_start[];
extern char kernel_end[];
// invalidate page cache at a vitural address
-static inline void invlpg(volatile void *vADDR)
+static inline void invlpg(volatile const void *vADDR)
{
__asm__ volatile("invlpg (%0)" ::"r"(vADDR) : "memory");
}
/* map */
-// map a physical pml4 address to access
+// map a physical address to a virtural address
// @returns VIRTUAL ADDRESS
-static volatile struct pml4 *pml4_map(volatile struct pml4 *pPML4)
+static volatile void *map_addr(volatile const void *pADDR, size_t pt_idx)
{
- static struct pml4 *vPML4 = (void *)(uintptr_t)0x40000000;
- static volatile struct pte *vPTE = &paging_pt.entries[0];
-
- if ((uint64_t)pPML4 >> 12 == vPTE->address)
- return vPML4;
+ volatile char *vADDR;
+ volatile struct pte *vPTE;
- vPTE->address = (uint64_t)pPML4 >> 12;
- vPTE->flags = F_PRESENT | F_WRITEABLE;
- invlpg(vPML4);
- return vPML4;
-}
+ assert(pt_idx < 512, "invalid page table entry index");
-// map a physical pdpt address to access
-// @returns VIRTUAL ADDRESS
-static volatile struct pdpt *pdpt_map(volatile struct pdpt *pPDPT)
-{
- static struct pdpt *vPDPT = (void *)(uintptr_t)0x40001000;
- static volatile struct pte *vPTE = &paging_pt.entries[1];
+ vADDR = (char *)(uintptr_t)(0x40000000 + pt_idx * PAGE_SIZE);
+ vPTE = &paging_pt.entries[pt_idx];
- if ((uint64_t)pPDPT >> 12 == vPTE->address)
- return vPDPT;
+ if ((uint64_t)pADDR >> 12 == vPTE->address)
+ return vADDR;
- vPTE->address = (uint64_t)pPDPT >> 12;
+ vPTE->address = (uint64_t)pADDR >> 12;
vPTE->flags = F_PRESENT | F_WRITEABLE;
- invlpg(vPDPT);
- return vPDPT;
+ invlpg(vADDR);
+ return vADDR;
}
-// map a physical pd address to access
-// @returns VIRTUAL ADDRESS
-static volatile struct pd *pd_map(volatile struct pd *pPD)
-{
- static struct pd *vPD = (void *)(uintptr_t)0x40002000;
- static volatile struct pte *vPTE = &paging_pt.entries[2];
-
- if ((uint64_t)pPD >> 12 == vPTE->address)
- return vPD;
+#define PML4_MAP(pADDR) (volatile struct pml4 *)map_addr(pADDR, 0)
+#define PML4_MAPC(pADDR) (volatile const struct pml4 *)map_addr(pADDR, 4)
- vPTE->address = (uint64_t)pPD >> 12;
- vPTE->flags = F_PRESENT | F_WRITEABLE;
- invlpg(vPD);
- return vPD;
-}
+#define PDPT_MAP(pADDR) (volatile struct pdpt *)map_addr(pADDR, 1)
+#define PDPT_MAPC(pADDR) (volatile const struct pdpt *)map_addr(pADDR, 5)
-// map a physical pt address to access
-// @returns VIRTUAL ADDRESS
-static volatile struct pt *pt_map(volatile struct pt *pPT)
-{
- static struct pt *vPT = (void *)(uintptr_t)0x40003000;
- static volatile struct pte *vPTE = &paging_pt.entries[3];
+#define PD_MAP(pADDR) (volatile struct pd *)map_addr(pADDR, 2)
+#define PD_MAPC(pADDR) (volatile const struct pd *)map_addr(pADDR, 6)
- if ((uint64_t)pPT >> 12 == vPTE->address)
- return vPT;
+#define PT_MAP(pADDR) (volatile struct pt *)map_addr(pADDR, 3)
+#define PT_MAPC(pADDR) (volatile const struct pt *)map_addr(pADDR, 7)
- vPTE->address = (uint64_t)pPT >> 12;
- vPTE->flags = F_PRESENT | F_WRITEABLE;
- invlpg(vPT);
- return vPT;
-}
+#define PAGE_MAP(pADDR) (volatile void *)map_addr(pADDR, 8)
+#define PAGE_MAPC(pADDR) (volatile const void *)map_addr(pADDR, 9)
/* locate */
// locate a pdpt for a vitural address
// @returns PHYSICAL ADDRESS
static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4,
- void *vADDR)
+ const void *vADDR)
{
volatile struct pml4 *vPML4;
volatile struct pml4e *vPML4E;
@@ -222,7 +195,7 @@ static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4,
uint64_t offset;
offset = (uint64_t)vADDR >> 39;
- vPML4 = pml4_map(pPML4);
+ vPML4 = PML4_MAP(pPML4);
vPML4E = &vPML4->entries[offset];
if (vPML4E->flags & F_PRESENT) {
@@ -235,7 +208,8 @@ static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4,
// locate a pd for a vitural address
// @returns PHYSICAL ADDRESS
-static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, void *vADDR)
+static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT,
+ const void *vADDR)
{
volatile struct pdpt *vPDPT;
volatile struct pdpte *vPDPTE;
@@ -243,7 +217,7 @@ static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, void *vADDR)
uint64_t offset;
offset = ((uint64_t)vADDR >> 30) & 0x1ff;
- vPDPT = pdpt_map(pPDPT);
+ vPDPT = PDPT_MAP(pPDPT);
vPDPTE = &vPDPT->entries[offset];
if (vPDPTE->flags & F_PRESENT) {
@@ -256,7 +230,7 @@ static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, void *vADDR)
// locate a pt for a vitural address
// @returns PHYSICAL ADDRESS
-static volatile struct pt *pt_locate(volatile struct pd *pPD, void *vADDR)
+static volatile struct pt *pt_locate(volatile struct pd *pPD, const void *vADDR)
{
volatile struct pd *vPD;
volatile struct pde *vPDE;
@@ -264,7 +238,7 @@ static volatile struct pt *pt_locate(volatile struct pd *pPD, void *vADDR)
uint64_t offset;
offset = ((uint64_t)vADDR >> 21) & 0x1ff;
- vPD = pd_map(pPD);
+ vPD = PD_MAP(pPD);
vPDE = &vPD->entries[offset];
if (vPDE->flags & F_PRESENT) {
@@ -287,7 +261,7 @@ static volatile struct pml4 *pml4_alloc(void)
if (pPML4 == NULL)
return NULL;
- vPML4 = pml4_map(pPML4);
+ vPML4 = PML4_MAP(pPML4);
memsetv(vPML4, 0, sizeof(struct pml4));
return pPML4;
}
@@ -303,7 +277,7 @@ static volatile struct pdpt *pdpt_alloc(volatile struct pml4 *pPML4,
uint64_t offset;
offset = (uint64_t)vADDR >> 39;
- vPML4 = pml4_map(pPML4);
+ vPML4 = PML4_MAP(pPML4);
vPML4E = &vPML4->entries[offset];
pPDPT = pdpt_locate(pPML4, vADDR);
@@ -316,7 +290,7 @@ static volatile struct pdpt *pdpt_alloc(volatile struct pml4 *pPML4,
if (pPML4 == NULL)
return NULL;
- vPDPT = pdpt_map(pPDPT);
+ vPDPT = PDPT_MAP(pPDPT);
memsetv(vPDPT, 0, sizeof(struct pdpt));
vPML4E->address = (uintptr_t)pPDPT >> 12;
vPML4E->flags = F_PRESENT | flags;
@@ -336,7 +310,7 @@ static volatile struct pd *pd_alloc(volatile struct pdpt *pPDPT, void *vADDR,
uint64_t offset;
offset = ((uint64_t)vADDR >> 30) & 0x1ff;
- vPDPT = pdpt_map(pPDPT);
+ vPDPT = PDPT_MAP(pPDPT);
vPDPTE = &vPDPT->entries[offset];
pPD = pd_locate(pPDPT, vADDR);
@@ -349,7 +323,7 @@ static volatile struct pd *pd_alloc(volatile struct pdpt *pPDPT, void *vADDR,
if (pPDPT == NULL)
return NULL;
- vPD = pd_map(pPD);
+ vPD = PD_MAP(pPD);
memsetv(vPD, 0, sizeof(struct pd));
vPDPTE->address = (uintptr_t)pPD >> 12;
vPDPTE->flags = F_PRESENT | flags;
@@ -369,7 +343,7 @@ static volatile struct pt *pt_alloc(volatile struct pd *pPD, void *vADDR,
uint64_t offset;
offset = ((uint64_t)vADDR >> 21) & 0x1ff;
- vPD = pd_map(pPD);
+ vPD = PD_MAP(pPD);
vPDE = &vPD->entries[offset];
pPT = pt_locate(pPD, vADDR);
@@ -382,7 +356,7 @@ static volatile struct pt *pt_alloc(volatile struct pd *pPD, void *vADDR,
if (pPD == NULL)
return NULL;
- vPT = pt_map(pPT);
+ vPT = PT_MAP(pPT);
memsetv(vPT, 0, sizeof(struct pt));
vPDE->address = (uintptr_t)pPT >> 12;
vPDE->flags = F_PRESENT | flags;
@@ -398,7 +372,7 @@ static void pt_free(volatile struct pt *pPT, bool force)
volatile struct pt *vPT;
uint64_t count;
- vPT = pt_map(pPT);
+ vPT = PT_MAP(pPT);
count = (vPT->count_high << 2) | vPT->count_low;
if (!count)
@@ -409,11 +383,18 @@ static void pt_free(volatile struct pt *pPT, bool force)
void *pADDR;
vPTE = &vPT->entries[i];
- if (!force && !(vPTE->flags & F_PRESENT))
+ if (!(vPTE->flags & F_PRESENT))
continue;
pADDR = (void *)((uintptr_t)vPTE->address << 12);
free_phys_page(pADDR);
+ count--;
+ }
+
+ if (!force && count) {
+ vPT->count_low = count;
+ vPT->count_high = count >> 2;
+ return;
}
free:
@@ -425,7 +406,7 @@ static void pd_free(volatile struct pd *pPD, bool force)
volatile struct pd *vPD;
uint64_t count;
- vPD = pd_map(pPD);
+ vPD = PD_MAP(pPD);
count = vPD->count;
if (!count)
@@ -436,11 +417,17 @@ static void pd_free(volatile struct pd *pPD, bool force)
volatile struct pt *pPT;
vPDE = &vPD->entries[i];
- if (!force && !(vPDE->flags & F_PRESENT))
+ if (!(vPDE->flags & F_PRESENT))
continue;
pPT = (volatile struct pt *)((uintptr_t)vPDE->address << 12);
pt_free(pPT, force);
+ count--;
+ }
+
+ if (!force && count) {
+ vPD->count = count;
+ return;
}
free:
@@ -452,7 +439,7 @@ static void pdpt_free(volatile struct pdpt *pPDPT, bool force)
volatile struct pdpt *vPDPT;
uint64_t count;
- vPDPT = pdpt_map(pPDPT);
+ vPDPT = PDPT_MAP(pPDPT);
count = vPDPT->count;
if (!count)
@@ -463,11 +450,17 @@ static void pdpt_free(volatile struct pdpt *pPDPT, bool force)
volatile struct pd *pPD;
vPDPTE = &vPDPT->entries[i];
- if (!force && !(vPDPTE->flags & F_PRESENT))
+ if (!(vPDPTE->flags & F_PRESENT))
continue;
pPD = (volatile struct pd *)((uintptr_t)vPDPTE->address << 12);
pd_free(pPD, force);
+ count--;
+ }
+
+ if (!force && count) {
+ vPDPT->count = count;
+ return;
}
free:
@@ -479,7 +472,7 @@ static void pml4_free(volatile struct pml4 *pPML4, bool force)
volatile struct pml4 *vPML4;
uint64_t count;
- vPML4 = pml4_map(pPML4);
+ vPML4 = PML4_MAP(pPML4);
count = vPML4->count;
if (!count)
@@ -490,23 +483,237 @@ static void pml4_free(volatile struct pml4 *pPML4, bool force)
volatile struct pdpt *pPDPT;
vPML4E = &vPML4->entries[i];
- if (!force && !(vPML4E->flags & F_PRESENT))
+ if (!(vPML4E->flags & F_PRESENT))
continue;
pPDPT = (volatile struct pdpt *)((uintptr_t)vPML4E->address << 12);
pdpt_free(pPDPT, force);
+ count--;
+ }
+
+ if (!force && count) {
+ vPML4->count = count;
+ return;
}
free:
free_phys_page((void *)(uintptr_t)pPML4);
}
+/* clone */
+
+volatile void *page_clone(volatile void *old_pADDR, bool cow)
+{
+ volatile const void *old_vADDR;
+ volatile void *new_pADDR, *new_vADDR;
+
+ // TODO: cow
+ (void)cow;
+
+ // dont reallocate kernel memeory!!
+ if ((volatile char *)old_pADDR <= kernel_end)
+ return old_pADDR;
+
+ new_pADDR = alloc_phys_page();
+ if (new_pADDR == NULL)
+ return NULL;
+
+ old_vADDR = PAGE_MAPC(old_pADDR);
+ new_vADDR = PAGE_MAP(new_pADDR);
+ memcpyv(new_vADDR, old_vADDR, PAGE_SIZE);
+ return new_pADDR;
+}
+
+volatile struct pt *pt_clone(volatile const struct pt *old_pPT, bool cow)
+{
+ volatile const struct pt *old_vPT;
+ volatile struct pt *new_pPT, *new_vPT;
+
+ new_pPT = alloc_phys_page();
+ if (new_pPT == NULL)
+ return NULL;
+
+ old_vPT = PT_MAPC(old_pPT);
+ new_vPT = PT_MAP(new_pPT);
+ memsetv(new_vPT, 0, PAGE_SIZE);
+
+ new_vPT->count_high = old_vPT->count_high;
+ new_vPT->count_low = old_vPT->count_low;
+
+ for (size_t i = 0; i < 512; i++) {
+ volatile const struct pte *old_vPTE;
+ volatile struct pte *new_vPTE;
+ volatile void *old_pADDR, *new_pADDR;
+
+ old_vPTE = &old_vPT->entries[i];
+ new_vPTE = &new_vPT->entries[i];
+
+ new_vPTE->execute_disable = old_vPTE->execute_disable;
+ new_vPTE->flags = old_vPTE->flags;
+ if (!(old_vPTE->flags & F_PRESENT))
+ continue;
+
+ new_vPTE->execute_disable = old_vPTE->execute_disable;
+ new_vPTE->flags = old_vPTE->flags;
+
+ old_pADDR = (volatile void *)((uintptr_t)old_vPTE->address << 12);
+ new_pADDR = page_clone(old_pADDR, cow);
+ if (new_pADDR == NULL)
+ goto fail;
+
+ new_vPTE->address = (uint64_t)new_pADDR >> 12;
+ }
+
+ return new_pPT;
+
+fail:
+ pt_free(new_pPT, true);
+ return NULL;
+}
+
+volatile struct pd *pd_clone(volatile const struct pd *old_pPD, bool cow)
+{
+ volatile const struct pd *old_vPD;
+ volatile struct pd *new_pPD, *new_vPD;
+
+ new_pPD = alloc_phys_page();
+ if (new_pPD == NULL)
+ return NULL;
+
+ old_vPD = PD_MAPC(old_pPD);
+ new_vPD = PD_MAP(new_pPD);
+ memsetv(new_vPD, 0, PAGE_SIZE);
+
+ new_vPD->count = old_vPD->count;
+
+ for (size_t i = 0; i < 512; i++) {
+ volatile const struct pde *old_vPDE;
+ volatile struct pde *new_vPDE;
+ volatile const struct pt *old_pPT;
+ volatile struct pt *new_pPT;
+
+ old_vPDE = &old_vPD->entries[i];
+ new_vPDE = &new_vPD->entries[i];
+
+ new_vPDE->execute_disable = old_vPDE->execute_disable;
+ new_vPDE->flags = old_vPDE->flags;
+ if (!(old_vPDE->flags & F_PRESENT))
+ continue;
+
+ old_pPT =
+ (volatile const struct pt *)((uintptr_t)old_vPDE->address << 12);
+ new_pPT = pt_clone(old_pPT, cow);
+ if (new_pPT == NULL)
+ goto fail;
+
+ new_vPDE->address = (uint64_t)new_pPT >> 12;
+ }
+
+ return new_pPD;
+
+fail:
+ pd_free(new_pPD, true);
+ return NULL;
+}
+
+volatile struct pdpt *pdpt_clone(volatile const struct pdpt *old_pPDPT,
+ bool cow)
+{
+ volatile const struct pdpt *old_vPDPT;
+ volatile struct pdpt *new_pPDPT, *new_vPDPT;
+
+ new_pPDPT = alloc_phys_page();
+ if (new_pPDPT == NULL)
+ return NULL;
+
+ old_vPDPT = PDPT_MAPC(old_pPDPT);
+ new_vPDPT = PDPT_MAP(new_pPDPT);
+ memsetv(new_vPDPT, 0, PAGE_SIZE);
+
+ new_vPDPT->count = old_vPDPT->count;
+
+ for (size_t i = 0; i < 512; i++) {
+ volatile const struct pdpte *old_vPDPTE;
+ volatile struct pdpte *new_vPDPTE;
+ volatile const struct pd *old_pPD;
+ volatile struct pd *new_pPD;
+
+ old_vPDPTE = &old_vPDPT->entries[i];
+ new_vPDPTE = &new_vPDPT->entries[i];
+
+ new_vPDPTE->execute_disable = old_vPDPTE->execute_disable;
+ new_vPDPTE->flags = old_vPDPTE->flags;
+ if (!(old_vPDPTE->flags & F_PRESENT))
+ continue;
+
+ old_pPD =
+ (volatile const struct pd *)((uintptr_t)old_vPDPTE->address << 12);
+ new_pPD = pd_clone(old_pPD, cow);
+ if (new_pPD == NULL)
+ goto fail;
+
+ new_vPDPTE->address = (uint64_t)new_pPD >> 12;
+ }
+
+ return new_pPDPT;
+
+fail:
+ pdpt_free(new_pPDPT, true);
+ return NULL;
+}
+
+volatile struct pml4 *pml4_clone(volatile const struct pml4 *old_pPML4,
+ bool cow)
+{
+ volatile const struct pml4 *old_vPML4;
+ volatile struct pml4 *new_pPML4, *new_vPML4;
+
+ new_pPML4 = pml4_alloc();
+ if (new_pPML4 == NULL)
+ return NULL;
+
+ old_vPML4 = PML4_MAPC(old_pPML4);
+ new_vPML4 = PML4_MAP(new_pPML4);
+
+ new_vPML4->count = old_vPML4->count;
+
+ for (size_t i = 0; i < 512; i++) {
+ volatile const struct pml4e *old_vPML4E;
+ volatile struct pml4e *new_vPML4E;
+ volatile const struct pdpt *old_pPDPT;
+ volatile struct pdpt *new_pPDPT;
+
+ old_vPML4E = &old_vPML4->entries[i];
+ new_vPML4E = &new_vPML4->entries[i];
+
+ new_vPML4E->execute_disable = old_vPML4E->execute_disable;
+ new_vPML4E->flags = old_vPML4E->flags;
+ if (!(old_vPML4E->flags & F_PRESENT))
+ continue;
+
+ old_pPDPT =
+ (volatile const struct pdpt *)((uintptr_t)old_vPML4E->address
+ << 12);
+ new_pPDPT = pdpt_clone(old_pPDPT, cow);
+ if (new_pPDPT == NULL)
+ goto fail;
+
+ new_vPML4E->address = (uint64_t)new_pPDPT >> 12;
+ }
+
+ return new_pPML4;
+
+fail:
+ pml4_free(new_pPML4, true);
+ return NULL;
+}
+
/* page specific */
// locate a pte for a vitural address
// @returns VIRTUAL ADDRESS
static volatile struct pte *page_locate(volatile struct pml4 *pPML4,
- void *vADDR)
+ const void *vADDR)
{
volatile struct pdpt *pPDPT;
volatile struct pd *pPD;
@@ -527,7 +734,7 @@ static volatile struct pte *page_locate(volatile struct pml4 *pPML4,
return NULL;
offset = ((uint64_t)vADDR >> 12) & 0x1ff;
- vPT = pt_map(pPT);
+ vPT = PT_MAP(pPT);
vPTE = &vPT->entries[offset];
if (vPTE->flags & F_PRESENT)
@@ -560,7 +767,7 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR,
return NULL;
offset = ((uint64_t)vADDR >> 12) & 0x1ff;
- vPT = pt_map(pPT);
+ vPT = PT_MAP(pPT);
vPTE = &vPT->entries[offset];
memsetv(vPTE, 0, sizeof(struct pte));
@@ -573,7 +780,8 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR,
}
// free a pte (page) for a vitural address
-static void page_free(volatile struct pml4 *pPML4, void *vADDR)
+static void page_free(volatile struct pml4 *pPML4, const void *vADDR,
+ bool deallocate)
{
volatile struct pte *vPTE;
void *pADDR;
@@ -585,17 +793,19 @@ static void page_free(volatile struct pml4 *pPML4, void *vADDR)
vPTE->flags = 0;
vPTE->address = 0;
- pADDR = (void *)((uintptr_t)vPTE->address << 12);
- free_phys_page(pADDR);
+ if (deallocate) {
+ pADDR = (void *)((uintptr_t)vPTE->address << 12);
+ free_phys_page(pADDR);
+ }
}
/* map & unmap pages */
-static void unmap_pages(volatile struct pml4 *pPML4, void *vADDR,
- long page_count)
+static void unmap_pages(volatile struct pml4 *pPML4, const void *vADDR,
+ long page_count, bool deallocate)
{
for (long i = 0; i < page_count; i++) {
- page_free(pPML4, vADDR);
+ page_free(pPML4, vADDR, deallocate);
vADDR = (char *)vADDR + PAGE_SIZE;
}
}
@@ -617,7 +827,7 @@ static int map_pages(volatile struct pml4 *pPML4, void *vADDR, void *pADDR,
return 0;
fail:
- unmap_pages(pPML4, vADDR, page_count);
+ unmap_pages(pPML4, vADDR, page_count, true);
return 1;
}
@@ -651,14 +861,14 @@ void paging_init(void)
kernel_pd_1.entries[0].flags = F_PRESENT | F_WRITEABLE;
kernel_pd_1.entries[0].address = (uint64_t)(paging_pt.entries) >> 12;
- memsetv(paging_pt.entries, 0, 4096);
+ memsetv(paging_pt.entries, 0, PAGE_SIZE);
// make sure we are using THESE pagetables
// EFI doesnt on boot
__asm__ volatile("mov %0, %%cr3" ::"r"(kernel_pml4.entries) : "memory");
}
-volatile void *paging_alloc(void)
+volatile void *pgdir_alloc(void)
{
volatile struct pml4 *pPML4;
@@ -666,8 +876,7 @@ volatile void *paging_alloc(void)
if (pPML4 == NULL)
return NULL;
- if (map_pages(pPML4, kernel_start, kernel_start,
- F_PRESENT | F_WRITEABLE,
+ if (map_pages(pPML4, kernel_start, kernel_start, F_PRESENT | F_WRITEABLE,
(kernel_end - kernel_start) / PAGE_SIZE)) {
pml4_free(pPML4, false);
return NULL;
@@ -676,31 +885,27 @@ volatile void *paging_alloc(void)
return pPML4;
}
-void paging_free(volatile void *addr)
+volatile void *pgdir_clone(volatile const void *old_pgdir, bool cow)
{
- pml4_free(addr, true);
+ return pml4_clone((volatile const struct pml4 *)old_pgdir, cow);
}
-static inline void *page_align(void *addr)
+void pgdir_free(volatile void *addr)
{
- uintptr_t a = (uintptr_t)addr;
- a /= PAGE_SIZE;
- a *= PAGE_SIZE;
- return (void *)a;
+ pml4_free(addr, true);
}
void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len,
unsigned int flags)
{
long pages;
- ptrdiff_t error;
+ size_t error;
void *aligned_phys;
- // get length and physical page aligned address
- aligned_phys = page_align(phys);
- error = (char *)phys - (char *)aligned_phys;
+ error = (size_t)phys % PAGE_SIZE;
len += error;
- pages = len / PAGE_SIZE + 1;
+ pages = (len + PAGE_SIZE - 1) / PAGE_SIZE;
+ aligned_phys = (char *)phys - error;
// get page aligned (or allocate) vitural address
if (virt == NULL)
@@ -708,6 +913,12 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len,
if (virt == NULL)
return NULL;
+ if (virtaddr_take(&ctx->virtctx, virt, pages))
+ return NULL;
+
+ assert((uint64_t)virt % PAGE_SIZE == 0,
+ "mem_mapaddr: vitural address not page aligned");
+
if (map_pages((volatile struct pml4 *)ctx->pml4, virt, aligned_phys,
F_PRESENT | flags, pages)) {
virtaddr_free(&ctx->virtctx, virt);
@@ -717,15 +928,74 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len,
return (char *)virt + error;
}
-void mem_unmapaddr(mem_ctx_t ctx, void *virt)
+void *kmapuseraddr(mem_ctx_t ctx, const void *usrADDR, size_t len)
+{
+ volatile struct pml4 *pml4;
+ char *pADDR, *vADDR;
+ size_t npages, error, i;
+
+ pml4 = (volatile struct pml4 *)kernel_mem_ctx->pml4;
+ npages = (len + PAGE_SIZE - 1) / PAGE_SIZE;
+ error = (size_t)usrADDR % PAGE_SIZE;
+ vADDR = virtaddr_alloc(&kernel_mem_ctx->virtctx, npages);
+ if (vADDR == NULL)
+ return NULL;
+
+ if (virtaddr_take(&kernel_mem_ctx->virtctx, vADDR, npages))
+ return NULL;
+
+ assert((size_t)vADDR % PAGE_SIZE == 0,
+ "kmapuseraddr: vitural address not page aligned");
+
+ for (i = 0; i < npages; i++) {
+ pADDR = mem_get_phys(ctx, (char *)usrADDR + i * PAGE_SIZE);
+ if (pADDR == NULL)
+ goto fail;
+
+ // page align
+ pADDR = (char *)(((size_t)pADDR / PAGE_SIZE) * PAGE_SIZE);
+
+ if (map_pages(pml4, vADDR + i * PAGE_SIZE, pADDR,
+ F_PRESENT | F_WRITEABLE, 1))
+ goto fail;
+ }
+
+ return vADDR + error;
+
+fail:
+ unmap_pages(&kernel_pml4, vADDR, i, false);
+ virtaddr_free(&kernel_mem_ctx->virtctx, vADDR);
+ return NULL;
+}
+
+void mem_unmapaddr(mem_ctx_t ctx, const void *virt)
{
+ long pages;
+
if (virt == NULL)
return;
- long pages = virtaddr_free(&ctx->virtctx, virt);
+ // page align
+ virt = (void *)(((size_t)virt / PAGE_SIZE) * PAGE_SIZE);
+
+ pages = virtaddr_free(&ctx->virtctx, virt);
if (pages < 1)
return;
- unmap_pages(&kernel_pml4, virt, pages);
+ unmap_pages(&kernel_pml4, virt, pages, false);
+}
+
+void *mem_get_phys(mem_ctx_t ctx, const void *vADDR)
+{
+ char *pADDR;
+ volatile struct pte *vPTE;
+
+ vPTE = page_locate((volatile struct pml4 *)ctx->pml4, vADDR);
+ if (vPTE == NULL)
+ return NULL;
+
+ pADDR = (void *)((uintptr_t)vPTE->address << 12);
+ pADDR += ((uint64_t)vADDR % PAGE_SIZE);
+ return pADDR;
}
void *mem_alloc_page(mem_ctx_t ctx, unsigned int flags)
@@ -755,24 +1025,71 @@ void *mem_alloc_pages(mem_ctx_t ctx, size_t count, unsigned int flags)
void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt,
unsigned int flags)
{
- void *phys = alloc_phys_pages(count);
- if (phys == NULL)
- return NULL;
+ size_t pages_needed = count;
- if (map_pages((volatile struct pml4 *)ctx->pml4, virt, phys, flags,
- count)) {
- if (phys)
- free_phys_pages(phys, count);
+ struct phys_page_slice prev_phys_block = PHYS_PAGE_SLICE_NULL;
+ struct phys_page_slice phys_pages;
+
+ if (virtaddr_take(&ctx->virtctx, virt, count))
return NULL;
+
+ while (pages_needed > 0) {
+ phys_pages = alloc_phys_page_withextra(pages_needed);
+ if (phys_pages.pagestart == NULL) {
+ goto mem_alloc_pages_at_fail;
+ }
+
+ {
+ // allocate the first page and store in it the physical address of the
+ // previous chunk of pages
+ // TODO: skip this if there are already enough pages from first alloc
+ void *pageone = kmapaddr(phys_pages.pagestart, NULL, 1,
+ F_PRESENT | F_WRITEABLE);
+ if (pageone == NULL) {
+ panic("kernel out of virtual memory");
+ }
+ *((struct phys_page_slice *)pageone) = prev_phys_block;
+ prev_phys_block = phys_pages;
+ kunmapaddr(pageone);
+ }
+
+ // index into virtual page array at index [count - pages_needed]
+ void *vaddr = ((uint8_t *)virt) + ((count - pages_needed) * PAGE_SIZE);
+
+ assert(pages_needed >= phys_pages.num_pages, "overflow");
+ pages_needed -= phys_pages.num_pages;
+
+ if (map_pages((volatile struct pml4 *)ctx->pml4, vaddr,
+ phys_pages.pagestart, flags, phys_pages.num_pages)) {
+ goto mem_alloc_pages_at_fail;
+ }
}
+
return virt;
+
+mem_alloc_pages_at_fail:
+ while (prev_phys_block.pagestart) {
+ void *virtpage = kmapaddr(prev_phys_block.pagestart, NULL, 1,
+ F_PRESENT | F_WRITEABLE);
+ if (!virtpage) {
+ // memory corruption, most likely a bug
+ // could also ERROR here and exit with leak
+ panic("unable to free memory from failed mem_alloc_pages_at call");
+ }
+ struct phys_page_slice prev = *(struct phys_page_slice *)virtpage;
+ prev_phys_block = prev;
+ free_phys_pages_slice(prev);
+ kunmapaddr(virtpage);
+ }
+
+ return NULL;
}
-void mem_free_pages(mem_ctx_t ctx, void *virt)
+void mem_free_pages(mem_ctx_t ctx, const void *virt)
{
if (virt == NULL)
return;
long pages = virtaddr_free(&ctx->virtctx, virt);
- unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages);
+ unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages, true);
}
diff --git a/kernel/memory/paging.h b/kernel/memory/paging.h
index d80a9bf..94b7260 100644
--- a/kernel/memory/paging.h
+++ b/kernel/memory/paging.h
@@ -9,9 +9,12 @@
#ifndef PAGING_H_
#define PAGING_H_
+#include <stdbool.h>
+
void paging_init(void);
-volatile void *paging_alloc(void);
-void paging_free(volatile void *addr);
+volatile void *pgdir_alloc(void);
+volatile void *pgdir_clone(volatile const void *pdir, bool cow);
+void pgdir_free(volatile void *addr);
#endif /* paging.h */
diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c
index b164358..8971bcf 100644
--- a/kernel/memory/physalloc.c
+++ b/kernel/memory/physalloc.c
@@ -4,20 +4,19 @@
#include "physalloc.h"
-extern char kernel_start;
-extern char kernel_end;
-#define kaddr(addr) ((uintptr_t)(&addr))
+extern char kernel_start[];
+extern char kernel_end[];
// between memory_start and kernel_start will be the bitmap
static uintptr_t memory_start = 0;
-static uint64_t *bitmap;
+static uint64_t *bitmap = NULL;
static uint64_t total_memory;
static uint64_t free_memory;
static uint64_t page_count;
static uint64_t segment_count;
struct memory_map phys_mmap;
-struct memory_segment *page_start;
+struct memory_segment *page_start = NULL;
static const char *segment_type_str[] = {
[SEG_TYPE_FREE] = "Free", [SEG_TYPE_RESERVED] = "Reserved",
@@ -50,6 +49,9 @@ static long page_idx(void *page)
int cur_page = 0;
for (uint64_t idx = 0; idx < segment_count; idx++) {
const struct memory_segment *m = page_start;
+ if (addr < m->addr) {
+ return -1;
+ }
if ((uintptr_t)m + m->len > addr) {
return cur_page + ((addr - m->addr) / PAGE_SIZE);
}
@@ -58,12 +60,12 @@ static long page_idx(void *page)
return -1;
}
-static inline bool bitmap_get(int i)
+static inline bool bitmap_get(size_t i)
{
return (bitmap[i / 64] >> i % 64) & 1;
}
-static inline void bitmap_set(int i, bool v)
+static inline void bitmap_set(size_t i, bool v)
{
if (v)
free_memory -= PAGE_SIZE;
@@ -76,17 +78,26 @@ static inline void bitmap_set(int i, bool v)
void *alloc_phys_page(void)
{
- return alloc_phys_pages(1);
+ return alloc_phys_pages_exact(1);
}
-void *alloc_phys_pages(int pages)
+void *alloc_phys_pages_exact(size_t pages)
{
if (pages < 1)
return NULL;
- int n_contiguous = 0;
- int free_region_start = 0;
- for (uint64_t i = 0; i < page_count; i++) {
+ if (bitmap == NULL || page_start == NULL) {
+ // temporary bump allocator
+ void *addr = (void *)memory_start;
+ assert(pages == 1,
+ "caller expects more pages, but is only getting one");
+ memory_start += PAGE_SIZE;
+ return addr;
+ }
+
+ size_t n_contiguous = 0;
+ size_t free_region_start = 0;
+ for (size_t i = 0; i < page_count; i++) {
bool free = !bitmap_get(i);
if (free) {
@@ -94,7 +105,7 @@ void *alloc_phys_pages(int pages)
free_region_start = i;
n_contiguous++;
if (n_contiguous == pages) {
- for (int j = 0; j < pages; j++)
+ for (size_t j = 0; j < pages; j++)
bitmap_set(free_region_start + j, true);
return page_at(free_region_start);
}
@@ -105,12 +116,54 @@ void *alloc_phys_pages(int pages)
return NULL;
}
+struct phys_page_slice alloc_phys_page_withextra(size_t max_pages)
+{
+ if (max_pages == 0)
+ return PHYS_PAGE_SLICE_NULL;
+
+ for (size_t i = 0; i < page_count; i++) {
+ const bool free = !bitmap_get(i);
+ if (!free)
+ continue;
+
+ // now allocated
+ bitmap_set(i, true);
+
+ // found at least one page, guaranteed to return valid slice at this
+ // point
+ struct phys_page_slice out = {
+ .pagestart = page_at(i),
+ .num_pages = 1,
+ };
+
+ // add some extra pages if possible
+ for (; out.num_pages < MIN(page_count - i, max_pages);
+ ++out.num_pages) {
+ // early return if max_pages isn't available
+ if (bitmap_get(i + out.num_pages)) {
+ return out;
+ }
+ bitmap_set(i + out.num_pages, true);
+ }
+
+ return out;
+ }
+
+ // only reachable if there is not a single free page in the bitmap
+ return PHYS_PAGE_SLICE_NULL;
+}
+
void free_phys_page(void *ptr)
{
free_phys_pages(ptr, 1);
}
-void free_phys_pages(void *ptr, int pages)
+void free_phys_pages_slice(struct phys_page_slice slice)
+{
+ free_phys_pages(slice.pagestart, slice.num_pages);
+}
+
+void free_phys_pages(void *ptr, size_t pages)
{
if (ptr == NULL)
return;
@@ -119,8 +172,8 @@ void free_phys_pages(void *ptr, int pages)
if (idx == -1)
return;
- for (int i = 0; i < pages; i++)
- bitmap_set(idx + pages, false);
+ for (size_t i = 0; i < pages; i++)
+ bitmap_set(idx + i, false);
}
static bool segment_invalid(const struct memory_segment *segment)
@@ -129,11 +182,11 @@ static bool segment_invalid(const struct memory_segment *segment)
return true;
if (segment->type != SEG_TYPE_FREE)
return true;
- if (segment->addr < kaddr(kernel_start))
+ if (segment->addr < (uintptr_t)kernel_start)
return true;
if (segment->addr + segment->len < memory_start)
return true;
- if (segment->addr + segment->len < kaddr(kernel_start))
+ if (segment->addr + segment->len < (uintptr_t)kernel_start)
return true;
return false;
}
@@ -147,7 +200,7 @@ static struct memory_segment clamp_segment(const struct memory_segment *segment)
if (memory_start)
start = memory_start;
else
- start = kaddr(kernel_end);
+ start = (uintptr_t)kernel_end;
if (segment->addr < start) {
addr = start;
@@ -192,7 +245,7 @@ void physalloc_init(struct memory_map *map)
long bitmap_pages = (page_count / 64 / PAGE_SIZE) + 1;
long bitmap_size = bitmap_pages * PAGE_SIZE;
- bitmap = (uint64_t *)page_align(kaddr(kernel_end));
+ bitmap = (uint64_t *)page_align((uintptr_t)kernel_end);
long page_area_size = segment_count * sizeof(struct memory_segment);
char *page_area_addr = (char *)bitmap + bitmap_size;
diff --git a/kernel/memory/physalloc.h b/kernel/memory/physalloc.h
index 7afe998..e279409 100644
--- a/kernel/memory/physalloc.h
+++ b/kernel/memory/physalloc.h
@@ -11,11 +11,31 @@
#include <comus/memory.h>
+/// Represents some contiguous physical pages
+struct phys_page_slice {
+ void *pagestart;
+ size_t num_pages;
+};
+
+#define PHYS_PAGE_SLICE_NULL \
+ ((struct phys_page_slice){ .pagestart = NULL, .num_pages = 0 })
+
/**
* Initalize the physical page allocator
*/
void physalloc_init(struct memory_map *map);
+/*
+ * Allocates the first page(s) it finds. Returns a pointer to that page
+ * and, if there are (up to max_pages) extra pages free after it, it allocates
+ * them as well.
+ *
+ * @param max_pages - the maximum number of pages to mark as allocated
+ * @returns a slice of all of the allocated pages, num_pages will be
+ * <= max_pages
+ */
+struct phys_page_slice alloc_phys_page_withextra(size_t max_pages);
+
/**
* Allocates a single physical page in memory
* @preturns the physical address of the page
@@ -23,10 +43,11 @@ void physalloc_init(struct memory_map *map);
void *alloc_phys_page(void);
/**
- * Allocates count physical pages in memory
- * @returns the physical address of the first page
+ * Allocates count contiguous physical pages in memory
+ * @returns the physical address of the first page, or NULL if no
+ * contiguous pages exist.
*/
-void *alloc_phys_pages(int count);
+void *alloc_phys_pages_exact(size_t count);
/**
* Frees a single physical page in memory
@@ -39,6 +60,12 @@ void free_phys_page(void *ptr);
* @param ptr - the physical address of the first page
* @param count - the number of pages in the list
*/
-void free_phys_pages(void *ptr, int count);
+void free_phys_pages(void *ptr, size_t count);
+
+/**
+ * Frees a slice of physical pages in memory
+ * @param slice - the pages to free
+ */
+void free_phys_pages_slice(struct phys_page_slice slice);
#endif /* physalloc.h */
diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c
index 0f4de93..0cbba33 100644
--- a/kernel/memory/virtalloc.c
+++ b/kernel/memory/virtalloc.c
@@ -1,5 +1,7 @@
+#include "lib/kio.h"
#include <lib.h>
#include <comus/memory.h>
+#include <stdint.h>
#include "virtalloc.h"
@@ -79,7 +81,7 @@ static void free_node(struct virt_ctx *ctx, struct virt_addr_node *node)
void virtaddr_init(struct virt_ctx *ctx)
{
struct virt_addr_node init = {
- .start = 0x40005000, // map after paging pt
+ .start = 0x50000000,
.end = 0x1000000000000, // 48bit memory address max
.next = NULL,
.prev = NULL,
@@ -96,6 +98,44 @@ void virtaddr_init(struct virt_ctx *ctx)
ctx->is_allocating = false;
}
+int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new)
+{
+ // copy over data
+ memcpy(new, old, sizeof(struct virt_ctx));
+
+ // allocate new space
+ new->alloc_nodes =
+ kalloc(sizeof(struct virt_addr_node) * new->alloc_node_count);
+ if (new->alloc_nodes == NULL)
+ return 1;
+
+ // update prev/next in new allocation space
+ update_node_ptrs(old->alloc_nodes, new->alloc_nodes, old->alloc_node_count,
+ new->alloc_node_count);
+
+ // update bootstrap nodes
+ for (size_t i = 0; i < new->used_node_count; i++) {
+ struct virt_addr_node *prev, *next;
+
+ if (i >= BOOTSTRAP_VIRT_ALLOC_NODES)
+ break;
+
+ // get prev
+ prev = i > 0 ? &new->bootstrap_nodes[i - 1] : NULL;
+ next = i < BOOTSTRAP_VIRT_ALLOC_NODES - 1 ?
+ &new->bootstrap_nodes[i + 1] :
+ NULL;
+
+ new->bootstrap_nodes[i].prev = prev;
+ new->bootstrap_nodes[i].next = next;
+ }
+
+ // get starting node
+ new->start_node = &new->bootstrap_nodes[0]; // for now
+
+ return 0;
+}
+
static void merge_back(struct virt_ctx *ctx, struct virt_addr_node *node)
{
while (node->prev) {
@@ -139,33 +179,69 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages)
if (node->is_alloc)
continue;
- if (length >= n_length) {
- struct virt_addr_node *new = get_node(ctx);
- if (node->prev != NULL) {
- node->prev->next = new;
- } else {
- ctx->start_node = new;
- }
- new->next = node;
- new->prev = node->prev;
- node->prev = new;
- new->start = node->start;
- new->end = new->start + n_length;
- node->start = new->end;
- new->is_alloc = true;
- new->is_used = true;
- new->next = node;
- void *mem = (void *)new->start;
- merge_back(ctx, new);
- merge_forward(ctx, new);
- return mem;
- }
+ if (length < n_length)
+ continue;
+
+ return (void *)node->start;
}
return NULL;
}
-long virtaddr_free(struct virt_ctx *ctx, void *virtaddr)
+int virtaddr_take(struct virt_ctx *ctx, const void *virt, int n_pages)
+{
+ if (n_pages < 1)
+ return 0;
+
+ long n_length = n_pages * PAGE_SIZE;
+ struct virt_addr_node *node = ctx->start_node;
+
+ for (; node != NULL; node = node->next) {
+ if (node->is_alloc)
+ continue;
+
+ if (node->start > (uintptr_t)virt ||
+ node->end < (uintptr_t)virt + n_length)
+ continue;
+
+ // create new node on left
+ if (node->start < (uintptr_t)virt) {
+ struct virt_addr_node *left = get_node(ctx);
+ left->next = node;
+ left->prev = node->prev;
+ left->start = node->start;
+ left->end = (uintptr_t)virt;
+ left->is_used = true;
+ left->is_alloc = false;
+ node->prev->next = left;
+ node->prev = left;
+ }
+
+ // create new node on right
+ if (node->end > (uintptr_t)virt + n_length) {
+ struct virt_addr_node *right = get_node(ctx);
+ right->prev = node;
+ right->next = node->next;
+ right->start = (uintptr_t)virt + n_length;
+ right->end = node->end;
+ right->is_used = true;
+ right->is_alloc = false;
+ node->next->prev = right;
+ node->next = right;
+ }
+
+ node->start = (uintptr_t)virt;
+ node->end = node->start + n_length;
+ node->is_alloc = true;
+ node->is_used = true;
+
+ return 0;
+ }
+
+ return 1;
+}
+
+long virtaddr_free(struct virt_ctx *ctx, const void *virtaddr)
{
if (virtaddr == NULL)
return -1;
diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h
index 7bf8b91..5033242 100644
--- a/kernel/memory/virtalloc.h
+++ b/kernel/memory/virtalloc.h
@@ -53,6 +53,11 @@ struct virt_ctx {
void virtaddr_init(struct virt_ctx *ctx);
/**
+ * Clone the virtual address allocator
+ */
+int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new);
+
+/**
* Allocate a virtual address of length x pages
* @param pages - x pages
* @returns virt addr
@@ -60,11 +65,19 @@ void virtaddr_init(struct virt_ctx *ctx);
void *virtaddr_alloc(struct virt_ctx *ctx, int pages);
/**
+ * Take (yoink) a predefined virtual address of length x pages
+ * @param virt - the start of the vitural address to take
+ * @param pages - x pages
+ * @returns 0 on success, 1 on err
+ */
+int virtaddr_take(struct virt_ctx *ctx, const void *virt, int pages);
+
+/**
* Free the virtual address from virtaddr_alloc
* @param virtaddr - the addr to free
* @returns number of pages used for virtaddr
*/
-long virtaddr_free(struct virt_ctx *ctx, void *virtaddr);
+long virtaddr_free(struct virt_ctx *ctx, const void *virtaddr);
/**
* Cleans up heap allocations and frees the virtalloc context
diff --git a/kernel/procs.c b/kernel/procs.c
index 9cde22f..9bf7508 100644
--- a/kernel/procs.c
+++ b/kernel/procs.c
@@ -1,7 +1,10 @@
+#include <comus/drivers/pit.h>
+#include <comus/syscalls.h>
+#include <comus/memory.h>
#include <comus/procs.h>
#include <comus/error.h>
#include <comus/cpu.h>
-#include <comus/memory.h>
+#include <comus/asm.h>
#define PCB_QUEUE_EMPTY(q) ((q)->head == NULL)
@@ -12,18 +15,16 @@ struct pcb_queue_s {
};
// collection of queues
-static struct pcb_queue_s pcb_freelist_queue;
-static struct pcb_queue_s ready_queue;
-static struct pcb_queue_s waiting_queue;
-static struct pcb_queue_s sleeping_queue;
-static struct pcb_queue_s zombie_queue;
+static struct pcb_queue_s _pcb_freelist;
+static struct pcb_queue_s _ready_queue;
+static struct pcb_queue_s _zombie_queue;
+static struct pcb_queue_s _syscall_queue[N_SYSCALLS];
// public facing queue handels
pcb_queue_t pcb_freelist;
-pcb_queue_t ready;
-pcb_queue_t waiting;
-pcb_queue_t sleeping;
-pcb_queue_t zombie;
+pcb_queue_t ready_queue;
+pcb_queue_t zombie_queue;
+pcb_queue_t syscall_queue[N_SYSCALLS];
/// pointer to the currently-running process
struct pcb *current_pcb = NULL;
@@ -35,7 +36,7 @@ struct pcb *init_pcb = NULL;
struct pcb ptable[N_PROCS];
/// next avaliable pid
-pid_t next_pid = 0;
+pid_t next_pid = 1;
static struct pcb *find_prev_wakeup(pcb_queue_t queue, struct pcb *pcb)
{
@@ -84,7 +85,7 @@ static struct pcb *find_prev_pid(pcb_queue_t queue, struct pcb *pcb)
// a macro to simplify queue setup
#define QINIT(q, s) \
- q = &q##_queue; \
+ q = &_##q; \
if (pcb_queue_reset(q, s) != SUCCESS) { \
panic("pcb_init can't reset " #q); \
}
@@ -96,10 +97,11 @@ void pcb_init(void)
// set up the external links to the queues
QINIT(pcb_freelist, O_PCB_FIFO);
- QINIT(ready, O_PCB_PRIO);
- QINIT(waiting, O_PCB_PID);
- QINIT(sleeping, O_PCB_WAKEUP);
- QINIT(zombie, O_PCB_PID);
+ QINIT(ready_queue, O_PCB_PRIO);
+ QINIT(zombie_queue, O_PCB_PID);
+ for (size_t i = 0; i < N_SYSCALLS; i++) {
+ QINIT(syscall_queue[i], O_PCB_PID);
+ }
// setup pcb linked list (free list)
// this can be done by calling pcb_free :)
@@ -119,6 +121,8 @@ int pcb_alloc(struct pcb **pcb)
if (pcb_queue_pop(pcb_freelist, &tmp) != SUCCESS)
return E_NO_PCBS;
+ tmp->pid = next_pid++;
+ tmp->state = PROC_STATE_NEW;
*pcb = tmp;
return SUCCESS;
}
@@ -177,46 +181,54 @@ void pcb_zombify(struct pcb *victim)
}
// schedule init if zombie child found
- if (zchild != NULL && init_pcb->state == PROC_STATE_WAITING) {
- assert(pcb_queue_remove(zombie, zchild) == SUCCESS,
+ if (zchild != NULL && init_pcb->syscall == SYS_waitpid) {
+ pid_t pid;
+ int *status;
+
+ assert(pcb_queue_remove(zombie_queue, zchild) == SUCCESS,
"pcb_zombify: cannot remove zombie process from queue");
- assert(pcb_queue_remove(waiting, init_pcb) == SUCCESS,
+ assert(pcb_queue_remove(syscall_queue[SYS_waitpid], init_pcb) ==
+ SUCCESS,
"pcb_zombify: cannot remove waiting process from queue");
- // send exited pid to init
- PCB_RET(init_pcb) = zchild->pid;
- // set &status in init's waitpid call
- int *ptr = (int *)PCB_ARG2(init_pcb);
- if (ptr != NULL) {
- mem_ctx_switch(init_pcb->memctx);
- *ptr = zchild->exit_status;
- mem_ctx_switch(kernel_mem_ctx);
+ pid = (pid_t)PCB_ARG1(init_pcb);
+ status = (int *)PCB_ARG2(init_pcb);
+
+ // set exited pid and exist status in init's waitpid call
+ if (pid == 0 || pid == zchild->pid) {
+ PCB_RET(init_pcb) = zchild->pid;
+ if (status != NULL) {
+ mem_ctx_switch(init_pcb->memctx);
+ *status = zchild->exit_status;
+ mem_ctx_switch(kernel_mem_ctx);
+ }
+ schedule(init_pcb);
}
- // schedule init and cleanup child
- schedule(init_pcb);
pcb_cleanup(zchild);
}
// if the parent is waiting, wake it up and clean the victim,
// otherwise the victim will become a zombie
- if (parent->state == PROC_STATE_WAITING) {
- // verify that the parent is either waiting for this process
- // or is waiting for any of its children
- uint64_t target = PCB_ARG1(parent);
+ if (parent->syscall == SYS_waitpid) {
+ pid_t pid;
+ int *status;
- if (target != 0 || target == victim->pid) {
- // send exited pid to parent
- PCB_RET(parent) = victim->pid;
- // send &status to parent
- int *ptr = (int *)PCB_ARG2(parent);
- if (ptr != NULL) {
+ pid = (pid_t)PCB_ARG1(parent);
+ status = (int *)PCB_ARG2(parent);
+
+ if (pid == 0 || pid == victim->pid) {
+ PCB_RET(parent) = zchild->pid;
+
+ assert(
+ pcb_queue_remove(syscall_queue[SYS_waitpid], parent) == SUCCESS,
+ "pcb_zombify: cannot remove parent process from waitpid queue");
+
+ if (status != NULL) {
mem_ctx_switch(parent->memctx);
- *ptr = victim->exit_status;
+ *status = victim->exit_status;
mem_ctx_switch(kernel_mem_ctx);
}
-
- // schedule the parent, and clean up the zombie
schedule(parent);
pcb_cleanup(victim);
return;
@@ -224,7 +236,7 @@ void pcb_zombify(struct pcb *victim)
}
victim->state = PROC_STATE_ZOMBIE;
- assert(pcb_queue_insert(zombie, victim) == SUCCESS,
+ assert(pcb_queue_insert(zombie_queue, victim) == SUCCESS,
"cannot insert victim process into zombie queue");
}
@@ -451,25 +463,74 @@ struct pcb *pcb_queue_peek(const pcb_queue_t queue)
void schedule(struct pcb *pcb)
{
assert(pcb != NULL, "schedule: pcb is null");
-
- if (pcb->state == PROC_STATE_KILLED)
- panic("attempted to schedule killed process %d", pcb->pid);
+ assert(pcb->state != PROC_STATE_UNUSED,
+ "attempted to schedule invalid process %d", pcb->pid);
+ assert(pcb->state != PROC_STATE_ZOMBIE,
+ "attempted to schedule killed process %d", pcb->pid);
pcb->state = PROC_STATE_READY;
+ pcb->syscall = 0;
- if (pcb_queue_insert(ready, pcb) != SUCCESS)
+ if (pcb_queue_insert(ready_queue, pcb) != SUCCESS)
panic("schedule insert fail");
}
-void dispatch(void)
+__attribute__((noreturn)) void dispatch(void)
{
+ int status;
+
assert(current_pcb == NULL, "dispatch: current process is not null");
- int status = pcb_queue_pop(ready, &current_pcb);
- if (status != SUCCESS)
- panic("dispatch queue remove failed, code %d", status);
+ // wait for a process to schedule
+ do {
+ status = pcb_queue_pop(ready_queue, &current_pcb);
+ if (status == SUCCESS) {
+ break;
+ }
+ int_wait();
+ } while (1);
// set the process up for success
+ current_pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(current_pcb->memctx);
current_pcb->state = PROC_STATE_RUNNING;
current_pcb->ticks = 3; // ticks per process
+ current_pcb->syscall = 0;
+
+ syscall_return();
+}
+
+void pcb_on_tick(void)
+{
+ // procs not initalized yet
+ if (init_pcb == NULL)
+ return;
+
+ // update on sleeping
+ do {
+ struct pcb *pcb;
+
+ if (pcb_queue_empty(syscall_queue[SYS_sleep]))
+ break;
+
+ pcb = pcb_queue_peek(syscall_queue[SYS_sleep]);
+ assert(pcb != NULL, "sleeping queue should not be empty");
+
+ if (pcb->wakeup >= ticks)
+ break;
+
+ if (pcb_queue_remove(syscall_queue[SYS_sleep], pcb))
+ panic("failed to wake sleeping process: %d", pcb->pid);
+
+ schedule(pcb);
+ } while (1);
+
+ if (current_pcb) {
+ current_pcb->ticks--;
+ if (current_pcb->ticks < 1) {
+ // schedule another process
+ schedule(current_pcb);
+ current_pcb = NULL;
+ dispatch();
+ }
+ }
}
diff --git a/kernel/syscall.c b/kernel/syscall.c
new file mode 100644
index 0000000..96d2fcf
--- /dev/null
+++ b/kernel/syscall.c
@@ -0,0 +1,374 @@
+#include <comus/user.h>
+#include <comus/cpu.h>
+#include <comus/syscalls.h>
+#include <comus/drivers/acpi.h>
+#include <comus/drivers/gpu.h>
+#include <comus/drivers/pit.h>
+#include <comus/memory.h>
+#include <comus/procs.h>
+#include <comus/time.h>
+#include <comus/error.h>
+#include <lib.h>
+#include <stddef.h>
+
+static struct pcb *pcb;
+
+#define RET(type, name) type *name = (type *)(&pcb->regs.rax)
+#define ARG1(type, name) type name = (type)(pcb->regs.rdi)
+#define ARG2(type, name) type name = (type)(pcb->regs.rsi)
+#define ARG3(type, name) type name = (type)(pcb->regs.rdx)
+#define ARG4(type, name) type name = (type)(pcb->regs.rcx)
+
+#define stdin 0
+#define stdout 1
+#define stderr 2
+
+__attribute__((noreturn)) static int sys_exit(void)
+{
+ ARG1(int, status);
+
+ pcb->exit_status = status;
+ pcb_zombify(pcb);
+
+ // call next process
+ dispatch();
+}
+
+static int sys_waitpid(void)
+{
+ // arguments are read later
+ // by procs.c
+ pcb->state = PROC_STATE_BLOCKED;
+ assert(pcb_queue_insert(syscall_queue[SYS_waitpid], pcb) == SUCCESS,
+ "sys_waitpid: could not add process to waitpid queue");
+
+ // call next process
+ dispatch();
+}
+
+static int sys_fork(void)
+{
+ struct pcb *child;
+
+ child = user_clone(pcb);
+ if (child == NULL)
+ return -1;
+
+ child->regs.rax = 0;
+ pcb->regs.rax = child->pid;
+ schedule(child);
+ return 0;
+}
+
+static int sys_write(void)
+{
+ ARG1(int, fd);
+ ARG2(const void *, buffer);
+ ARG3(size_t, nbytes);
+
+ const char *map_buf = kmapuseraddr(pcb->memctx, buffer, nbytes);
+ if (map_buf == NULL)
+ return 0;
+
+ // cannot write to stdin
+ if (fd == 0)
+ nbytes = 0;
+
+ // write to stdout / stderr
+ else if (fd == stdout || fd == stderr) {
+ for (size_t i = 0; i < nbytes; i++)
+ kputc(map_buf[i]);
+ }
+
+ // files
+ else {
+ // TODO: write to files
+ nbytes = 0;
+ }
+
+ kunmapaddr(map_buf);
+
+ return nbytes;
+}
+
+static int sys_getpid(void)
+{
+ return pcb->pid;
+}
+
+static int sys_getppid(void)
+{
+ // init's parent is itself
+ if (pcb->parent == NULL)
+ return init_pcb->pid;
+ return pcb->parent->pid;
+}
+
+static int sys_gettime(void)
+{
+ RET(unsigned long, time);
+ *time = unixtime();
+ return 0;
+}
+
+static int sys_getprio(void)
+{
+ RET(unsigned int, prio);
+ *prio = pcb->priority;
+ return 0;
+}
+
+static int sys_setprio(void)
+{
+ RET(unsigned int, old);
+ ARG1(unsigned int, new);
+
+ *old = pcb->priority;
+ pcb->priority = new;
+ return 0;
+}
+
+static int sys_kill(void)
+{
+ ARG1(pid_t, pid);
+ struct pcb *victim, *parent;
+
+ victim = pcb_find_pid(pid);
+
+ // pid does not exist
+ if (victim == NULL)
+ return 1;
+
+ parent = victim;
+ while (parent) {
+ if (parent->pid == pcb->pid)
+ break;
+ parent = parent->parent;
+ }
+
+ // we do not own this pid
+ if (parent == NULL)
+ return 1;
+
+ switch (victim->state) {
+ case PROC_STATE_ZOMBIE:
+ // you can't kill it if it's already dead
+ return 0;
+
+ case PROC_STATE_READY:
+ // remove from ready queue
+ victim->exit_status = 1;
+ pcb_queue_remove(ready_queue, victim);
+ pcb_zombify(victim);
+ return 0;
+
+ case PROC_STATE_BLOCKED:
+ // remove from syscall queue
+ victim->exit_status = 1;
+ pcb_queue_remove(syscall_queue[victim->syscall], victim);
+ pcb_zombify(victim);
+ return 0;
+
+ case PROC_STATE_RUNNING:
+ // we have met the enemy, and it is us!
+ pcb->exit_status = 1;
+ pcb_zombify(pcb);
+ // we need a new current process
+ dispatch();
+ break;
+
+ default:
+ // cannot kill a previable process
+ return 1;
+ }
+
+ return 0;
+}
+
+static int sys_sleep(void)
+{
+ RET(int, ret);
+ ARG1(unsigned long, ms);
+
+ if (ms == 0) {
+ *ret = 0;
+ schedule(pcb);
+ dispatch();
+ }
+
+ pcb->wakeup = ticks + ms;
+ if (pcb_queue_insert(syscall_queue[SYS_sleep], pcb)) {
+ WARN("sleep pcb insert failed");
+ return 1;
+ }
+ pcb->state = PROC_STATE_BLOCKED;
+
+ // calling pcb is in sleeping queue,
+ // we must call a new one
+ dispatch();
+}
+
+__attribute__((noreturn)) static int sys_poweroff(void)
+{
+ // TODO: we should probably
+ // kill all user processes
+ // and then sync the fs
+ acpi_shutdown();
+}
+
+static void *pcb_update_heap(intptr_t increment)
+{
+ char *curr_brk;
+ size_t curr_pages, new_pages, new_len;
+
+ new_len = pcb->heap_len + increment;
+ new_pages = (new_len + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ curr_brk = pcb->heap_start + pcb->heap_len;
+ curr_pages = (pcb->heap_len + PAGE_SIZE - 1) / PAGE_SIZE;
+ if (pcb->heap_len == 0)
+ curr_pages = 0;
+
+ // do nothing i guess
+ if (increment == 0 || new_pages == curr_pages)
+ return curr_brk;
+
+ // unmap pages if decreasing
+ if (new_pages < curr_pages) {
+ void *new_end = pcb->heap_start + new_pages * PAGE_SIZE;
+ mem_free_pages(pcb->memctx, new_end);
+ pcb->heap_len = new_pages * PAGE_SIZE;
+ }
+
+ // map pages if increasing
+ else {
+ void *curr_end = pcb->heap_start + curr_pages * PAGE_SIZE;
+ if (mem_alloc_pages_at(pcb->memctx, new_pages - curr_pages, curr_end,
+ F_PRESENT | F_WRITEABLE | F_UNPRIVILEGED) ==
+ NULL)
+ return NULL;
+ pcb->heap_len = new_pages * PAGE_SIZE;
+ }
+
+ return curr_brk;
+}
+
+static int sys_brk(void)
+{
+ RET(void *, brk);
+ ARG1(const void *, addr);
+
+ // cannot make heap smaller than start
+ if ((const char *)addr < pcb->heap_start) {
+ *brk = NULL;
+ return 0;
+ }
+
+ *brk = pcb_update_heap((intptr_t)addr -
+ ((intptr_t)pcb->heap_start + pcb->heap_len));
+ return 0;
+}
+
+static int sys_sbrk(void)
+{
+ RET(void *, brk);
+ ARG1(intptr_t, increment);
+
+ *brk = pcb_update_heap(increment);
+ return 0;
+}
+
+static int sys_drm(void)
+{
+ ARG1(void **, res_fb);
+ ARG2(int *, res_width);
+ ARG3(int *, res_height);
+ ARG4(int *, res_bpp);
+
+ void *pADDR, *vADDR;
+ int width, height, bpp;
+ size_t len;
+
+ if (gpu_dev == NULL)
+ return 1;
+
+ len = gpu_dev->width * gpu_dev->height * gpu_dev->bit_depth / 8;
+ pADDR =
+ mem_get_phys(kernel_mem_ctx, (void *)(uintptr_t)gpu_dev->framebuffer);
+ if (pADDR == NULL)
+ return 1;
+
+ vADDR = mem_mapaddr(pcb->memctx, pADDR, (void *)0x1000000000, len,
+ F_PRESENT | F_WRITEABLE | F_UNPRIVILEGED);
+ if (vADDR == NULL)
+ return 1;
+
+ width = gpu_dev->width;
+ height = gpu_dev->height;
+ bpp = gpu_dev->bit_depth;
+
+ mem_ctx_switch(pcb->memctx);
+ *res_fb = vADDR;
+ *res_width = width;
+ *res_height = height;
+ *res_bpp = bpp;
+ mem_ctx_switch(kernel_mem_ctx);
+
+ return 0;
+}
+
+static int sys_ticks(void)
+{
+ RET(uint64_t, res_ticks);
+ *res_ticks = ticks;
+ return 0;
+}
+
+static int (*syscall_tbl[N_SYSCALLS])(void) = {
+ [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid,
+ [SYS_fork] = sys_fork, [SYS_exec] = NULL,
+ [SYS_open] = NULL, [SYS_close] = NULL,
+ [SYS_read] = NULL, [SYS_write] = sys_write,
+ [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid,
+ [SYS_gettime] = sys_gettime, [SYS_getprio] = sys_getprio,
+ [SYS_setprio] = sys_setprio, [SYS_kill] = sys_kill,
+ [SYS_sleep] = sys_sleep, [SYS_brk] = sys_brk,
+ [SYS_sbrk] = sys_sbrk, [SYS_poweroff] = sys_poweroff,
+ [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks,
+};
+
+void syscall_handler(void)
+{
+ uint64_t num;
+ int (*handler)(void);
+ int ret = 1;
+
+ // update data
+ pcb = current_pcb;
+ num = pcb->regs.rax;
+ pcb->regs.rax = 0;
+ pcb->syscall = num;
+ current_pcb = NULL;
+
+ // check for invalid syscall
+ if (num >= N_SYSCALLS) {
+ // kill process
+ pcb->exit_status = 1;
+ pcb_zombify(pcb);
+ // call next process
+ dispatch();
+ }
+
+ // run syscall handler
+ handler = syscall_tbl[num];
+ if (handler != NULL)
+ ret = handler();
+
+ // on failure, set rax
+ if (ret)
+ pcb->regs.rax = ret;
+
+ // return to current pcb
+ pcb->syscall = 0;
+ current_pcb = pcb;
+}
diff --git a/kernel/user.c b/kernel/user.c
index 0a237e9..f9b541c 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -1,5 +1,265 @@
+#include <comus/fs.h>
#include <comus/procs.h>
#include <comus/memory.h>
+#include <comus/user.h>
+#include <elf.h>
+
+/// FIXME: the following code is using direct
+/// disk access instead of file access, this is
+/// because filesystems are not yet implemented.
+/// This MUST be changed once we have files.
+/// - Freya
+
+#define USER_STACK_TOP 0x800000000000
+#define USER_STACK_LEN (4 * PAGE_SIZE)
+
+#define BLOCK_SIZE (PAGE_SIZE * 1000)
+static uint8_t *load_buffer = NULL;
+
+#define USER_CODE 0x18
+#define USER_DATA 0x20
+#define RING3 3
+
+static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx)
+{
+ Elf64_Phdr hdr;
+ size_t mem_bytes, mem_pages;
+ size_t file_bytes, file_pages;
+ uint8_t *mapADDR;
+
+ hdr = pcb->elf_segments[idx];
+
+ // return if this is not a lodable segment
+ if (hdr.p_type != PT_LOAD)
+ return 0;
+
+ mem_bytes = hdr.p_memsz;
+ file_bytes = hdr.p_filesz;
+
+ // we cannot read more data to less memory
+ if (file_bytes > mem_bytes)
+ return 1;
+
+ mem_pages = (mem_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+ file_pages = (file_bytes + PAGE_SIZE - 1) / PAGE_SIZE;
+
+ // return if were reading no data
+ if (file_pages < 1)
+ return 0;
+
+ // allocate memory in user process
+ if (mem_alloc_pages_at(pcb->memctx, mem_pages, (void *)hdr.p_vaddr,
+ F_WRITEABLE | F_UNPRIVILEGED) == NULL)
+ return 1;
+
+ mapADDR = kmapuseraddr(pcb->memctx, (void *)hdr.p_vaddr, mem_bytes);
+ if (mapADDR == NULL)
+ return 1;
+
+ // load data
+ size_t total_read = 0;
+ while (total_read < file_bytes) {
+ size_t read = BLOCK_SIZE;
+ if (read > file_bytes - total_read)
+ read = file_bytes - total_read;
+ if ((read = disk_read(disk, hdr.p_offset + total_read, read,
+ load_buffer)) < 1) {
+ kunmapaddr(mapADDR);
+ return 1;
+ }
+ memcpy(mapADDR + total_read, load_buffer, read);
+ total_read += read;
+ }
+
+ // update heap end
+ if (hdr.p_vaddr + mem_pages * PAGE_SIZE > (uint64_t)pcb->heap_start)
+ pcb->heap_start = (void *)(hdr.p_vaddr + mem_pages * PAGE_SIZE);
+
+ kunmapaddr(mapADDR);
+ return 0;
+}
+
+static int user_load_segments(struct pcb *pcb, struct disk *disk)
+{
+ int ret = 0;
+
+ pcb->heap_start = NULL;
+ pcb->heap_len = 0;
+
+ if (load_buffer == NULL)
+ if ((load_buffer = kalloc(BLOCK_SIZE)) == NULL)
+ return 1;
+
+ for (int i = 0; i < pcb->n_elf_segments; i++)
+ if ((ret = user_load_segment(pcb, disk, i)))
+ return ret;
+
+ if (pcb->heap_start == NULL) {
+ WARN("No loadable ELF segments found.");
+ return 1;
+ };
+
+ return 0;
+}
+
+static int validate_elf_hdr(struct pcb *pcb)
+{
+ Elf64_Ehdr *ehdr = &pcb->elf_header;
+
+ if (strncmp((const char *)ehdr->e_ident, ELFMAG, SELFMAG)) {
+ WARN("Invalid ELF File.\n");
+ return 1;
+ }
+
+ if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) {
+ WARN("Unsupported ELF Class.\n");
+ return 1;
+ }
+
+ if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) {
+ ERROR("Unsupported ELF File byte order.\n");
+ return 1;
+ }
+
+ if (ehdr->e_machine != EM_X86_64) {
+ WARN("Unsupported ELF File target.\n");
+ return 1;
+ }
+
+ if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
+ WARN("Unsupported ELF File version.\n");
+ return 1;
+ }
+
+ if (ehdr->e_phnum > N_ELF_SEGMENTS) {
+ WARN("Too many ELF segments.\n");
+ return 1;
+ }
+
+ if (ehdr->e_type != ET_EXEC) {
+ ERROR("Unsupported ELF File type.\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int user_load_elf(struct pcb *pcb, struct disk *disk)
+{
+ int ret = 0;
+
+ ret = disk_read(disk, 0, sizeof(Elf64_Ehdr), &pcb->elf_header);
+ if (ret < 0)
+ return 1;
+
+ if (validate_elf_hdr(pcb))
+ return 1;
+
+ pcb->n_elf_segments = pcb->elf_header.e_phnum;
+ ret = disk_read(disk, pcb->elf_header.e_phoff,
+ sizeof(Elf64_Phdr) * pcb->elf_header.e_phnum,
+ &pcb->elf_segments);
+ if (ret < 0)
+ return 1;
+
+ return 0;
+}
+
+static int user_setup_stack(struct pcb *pcb)
+{
+ // allocate stack
+ if (mem_alloc_pages_at(pcb->memctx, USER_STACK_LEN / PAGE_SIZE,
+ (void *)(USER_STACK_TOP - USER_STACK_LEN),
+ F_WRITEABLE | F_UNPRIVILEGED) == NULL)
+ return 1;
+
+ memset(&pcb->regs, 0, sizeof(struct cpu_regs));
+
+ // pgdir
+ pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(pcb->memctx);
+ // segments
+ pcb->regs.gs = USER_DATA | RING3;
+ pcb->regs.fs = USER_DATA | RING3;
+ pcb->regs.es = USER_DATA | RING3;
+ pcb->regs.ds = USER_DATA | RING3;
+ // registers
+ pcb->regs.rdi = 0; // argc
+ pcb->regs.rsi = 0; // argv
+ // intruction pointer
+ pcb->regs.rip = pcb->elf_header.e_entry;
+ // code segment
+ pcb->regs.cs = USER_CODE | RING3;
+ // rflags
+ pcb->regs.rflags = (1 << 9);
+ // stack pointer
+ pcb->regs.rsp = USER_STACK_TOP;
+ // stack segment
+ pcb->regs.ss = USER_DATA | RING3;
+
+ return 0;
+}
+
+int user_load(struct pcb *pcb, struct disk *disk)
+{
+ // check inputs
+ if (pcb == NULL || disk == NULL)
+ return 1;
+
+ // allocate memory context
+ pcb->memctx = mem_ctx_alloc();
+ if (pcb->memctx == NULL)
+ goto fail;
+
+ // load elf information
+ if (user_load_elf(pcb, disk))
+ goto fail;
+
+ // load segments into memory
+ if (user_load_segments(pcb, disk))
+ goto fail;
+
+ // setup process stack
+ if (user_setup_stack(pcb))
+ goto fail;
+
+ // success
+ return 0;
+
+fail:
+ user_cleanup(pcb);
+ return 1;
+}
+
+struct pcb *user_clone(struct pcb *pcb)
+{
+ struct pcb *child;
+
+ if (pcb_alloc(&child))
+ return NULL;
+
+ // copy context
+ memcpy(&child->regs, &pcb->regs, sizeof(struct cpu_regs));
+ child->memctx = mem_ctx_clone(pcb->memctx, true);
+ if (child->memctx == NULL)
+ return NULL;
+
+ // set metadata
+ child->parent = pcb;
+ child->state = PROC_STATE_READY;
+ child->priority = pcb->priority;
+ child->ticks = 0;
+
+ // copy heap
+ child->heap_start = pcb->heap_start;
+ child->heap_len = pcb->heap_len;
+
+ // copy elf data
+ memcpy(&child->elf_header, &pcb->elf_header, sizeof(Elf64_Ehdr));
+ memcpy(&child->elf_segments, &pcb->elf_segments, sizeof(Elf64_Ehdr));
+ child->n_elf_segments = pcb->n_elf_segments;
+
+ return child;
+}
void user_cleanup(struct pcb *pcb)
{