commit - e5731e19a513e6a92d2b1d5dd1e57d1ef9c0a632
commit + 17683e896fc6162a038d5fb2711ca94055188dfb
blob - f1119d53a193b4a502931fdab8067c0e0c8ea8bf
blob + 89788503a89a7d78c692d45b4e8240c5b2eaa64f
--- alpha/main.c
+++ alpha/main.c
#include "syscalls/syscalls.h"
#define MAX_TASKS 64
+#define XHCI_ENTRY 0xC00000
struct task {
u8 assigned;
static struct task tasks[MAX_TASKS];
static void send_msg(const u8 *);
-static struct task* task_new(void);
+static struct task* task_new(void *);
void
alpha_main(struct mmap *km)
{
- struct task *p = task_new();
+ struct task *t = task_new((void *)XHCI_ENTRY);
+ struct sysc_context_switch scs;
- if (p == nil)
- send_msg("Alpha: failed to create task!\n");
+ if (t == nil)
+ send_msg("alpha: failed to create task!\n");
- send_msg("Alpha: running\n");
+ send_msg("alpha: running\n");
+
+ scs.sysc.type = SYSC_CONTEXT_SWITCH;
+ scs.threadid = t->thread;
+
+ sys_send((struct sysc *)&scs);
+
for (;;);
}
}
static struct task*
-task_new()
+task_new(void *entry)
{
+ struct sysc_new_thread snt;
+
+ snt.sysc.type = SYSC_NEW_THREAD;
+ snt.entry = entry;
+
for (int i = 0; i < MAX_TASKS; i++) {
if (tasks[i].assigned == 0) {
+ sys_send((struct sysc *)&snt);
+
+ if (snt.retid == -1)
+ break;
+
tasks[i].assigned = 1;
+ tasks[i].thread = snt.retid;
return &tasks[i];
}
}
blob - bffe5353e7d660182869ce421266cdebae9f98f8
blob + 206e351a6d3de7a304a5f92746e4f0296d04920a
--- boot.s
+++ boot.s
; Safety first!
xor ax, ax
mov ds, ax
+ mov es, ax
+ mov ss, ax
mov sp, 0x7c00 ; Stack under boot sector
; Save drive on boot and check LBA support
blob - a807dab563e01d327f6db6396f87182ce01d29fe
blob + ec4e1f9a0f50deb7371b258265b8470d750e8dec
--- boot2.s
+++ boot2.s
mov si, alpha_dap
call load_dap
+ mov si, xhci_dap
+ call load_dap
+
; Loading e820 blocks and values at kernel's entry
;
; Segmentation is required due to Real Mode limited
dw ALPHA_LOAD_ADDR >> 4
dq 1 + STAGE2_SECTORS + KERNEL_SECTORS
+xhci_dap:
+ db 0x10
+ db 0
+ dw XHCI_SECTORS
+ dw 0
+ dw XHCI_LOAD_ADDR >> 4
+ dq 1 + STAGE2_SECTORS + KERNEL_SECTORS + ALPHA_SECTORS
+
load_dap:
mov dl, [boot_drive]
mov ah, 0x42
mov ecx, (ALPHA_SECTORS * 512) / 4
rep movsd
+ ; Copy xhci
+ mov esi, XHCI_LOAD_ADDR
+ mov edi, XHCI_ENTRY
+ mov ecx, (XHCI_SECTORS * 512) / 4
+ rep movsd
+
; Update kernel module
mov DWORD [BINFO_KERNEL_ADDR], KERNEL_ENTRY
mov DWORD [BINFO_KERNEL_ADDR + 4], KERNEL_SECTORS * 512
; Update alpha module
mov DWORD [BINFO_ALPHA_ADDR], ALPHA_ENTRY
mov DWORD [BINFO_ALPHA_ADDR + 4], ALPHA_SECTORS * 32
+
+ ; Update xhci module
+ mov DWORD [BINFO_XHCI_ADDR], XHCI_ENTRY
+ mov DWORD [BINFO_XHCI_ADDR + 4], XHCI_SECTORS * 32
; Check for longmode support
mov eax, 0x80000000
mov rsp, 0x90000
mov rdi, BINFO_ADDR ; Kernel info
+ movzx rsi, byte [abs boot_drive]
mov rax, KERNEL_ENTRY
jmp rax
end:
STAGE2_SECTORS equ (end - start) / 512
-E820_COUNT_ADDR equ BINFO_ALPHA_ADDR + 8
+E820_COUNT_ADDR equ BINFO_XHCI_ADDR + 8
E820_PTR_ADDR equ E820_COUNT_ADDR + 8
E820_BLOCK_ADDR equ E820_PTR_ADDR + 8
blob - 8a3993143a938b35c65caf3c670a52119187d2d2
blob + 56896c243a94edf9e13fba720973564503dbf7c1
--- build.sh
+++ build.sh
ALPHA_SIZE=$(wc -c < $ALPHA_BIN)
ALPHA_SECTORS=$(( (ALPHA_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE))
+XHCI_BIN=servers/xhci/xhci.bin
+XHCI_SIZE=$(wc -c < $XHCI_BIN)
+XHCI_SECTORS=$(( (XHCI_SIZE + SECTOR_SIZE - 1) / SECTOR_SIZE))
+
echo "$OS_NAME: building"
nasm -f elf64 -o io.o $KERNEL_DIR/io.s
sysentry.o kthreads.o
KSIZE=$(wc -c < kerneli.bin)
-KSECTORS=$(( (KSIZE + SECTOR_SIZE - 1) / SECTOR_SIZE + 1)) # Extra sector
+KSECTORS=$(( (KSIZE + SECTOR_SIZE - 1) / SECTOR_SIZE + 2)) # Extra sector
KSIZE=$((KSECTORS * SECTOR_SIZE))
cat kerneli.bin /dev/zero | dd of=kernel.bin bs=$KSIZE count=1
-D ALPHA_SECTORS=$ALPHA_SECTORS \
-D KERNEL_ENTRY=$KERNEL_ENTRY \
-D ALPHA_ENTRY=$ALPHA_ENTRY \
+ -D XHCI_ENTRY=$XHCI_ENTRY \
+ -D XHCI_SECTORS=$XHCI_SECTORS \
-D BINFO_ADDR=$BINFO_ADDR \
-D KERNEL_LOAD_ADDR=$KERNEL_LOAD_ADDR \
-D ALPHA_LOAD_ADDR=$ALPHA_LOAD_ADDR \
+ -D XHCI_LOAD_ADDR=$XHCI_LOAD_ADDR \
-D BINFO_KERNEL_ADDR=$BINFO_KERNEL_ADDR \
-D BINFO_ALPHA_ADDR=$BINFO_ALPHA_ADDR \
+ -D BINFO_XHCI_ADDR=$BINFO_XHCI_ADDR \
boot2.s -o boot2.bin
STAGE2_SIZE=$(wc -c < boot2.bin)
BOOT_SECTORS=$((STAGE2_SECTORS + 1)) # Boot sector is 1 sector so we add
BOOT_SIZE=$((BOOT_SECTORS * SECTOR_SIZE))
-IMGSIZE=$(((KSECTORS * SECTOR_SIZE) + BOOT_SIZE + ALPHA_SIZE))
+IMGSIZE=$(((KSECTORS * SECTOR_SIZE) + BOOT_SIZE + ALPHA_SIZE + XHCI_SIZE))
-nasm \
- -D STAGE2_SECTORS=$STAGE2_SECTORS \
- -D KERNEL_SECTORS=$KSECTORS \
- -D ALPHA_SECTORS=$ALPHA_SECTORS \
- -D KERNEL_LOAD_ADDR=$KERNEL_LOAD_ADDR \
- -D ALPHA_LOAD_ADDR=$ALPHA_LOAD_ADDR \
- -D BINFO_ADDR=$BINFO_ADDR \
- -D BINFO_KERNEL_ADDR=$BINFO_KERNEL_ADDR \
- -D BINFO_ALPHA_ADDR=$BINFO_ALPHA_ADDR \
- boot.s -o boot.bin
+nasm -D STAGE2_SECTORS=$STAGE2_SECTORS boot.s -o boot.bin
cat boot2.bin /dev/zero | dd of=boot2i.bin bs=$STAGE2_SIZE count=1
-cat boot.bin boot2i.bin kernel.bin $ALPHA_BIN /dev/zero | dd of=$OS_NAME bs=$IMGSIZE count=1
+cat boot.bin boot2i.bin kernel.bin $ALPHA_BIN $XHCI_BIN /dev/zero | dd of=$OS_NAME bs=$IMGSIZE count=1
# This is so qemu doesn't bother us but really the OS is not that size
if (( IMG_SIZE < 0x100000 )) then
blob - 954a99bc381daa4b70b5b6f0b7dd6fae9e8d1040
blob + fa5d1ad7b193b5c6d07d406a9aaaac250743e385
--- include
+++ include
BINFO_ADDR=0x20000
BINFO_KERNEL_ADDR=$((BINFO_ADDR))
BINFO_ALPHA_ADDR=$((BINFO_KERNEL_ADDR + 8))
+BINFO_XHCI_ADDR=$((BINFO_ALPHA_ADDR + 8))
blob - 6c27160322ee571ec650f882cdcdf8100e2b06d0
blob + c03eeaa10e4b75159709cacf3ae014e5987bf1f1
--- kernel/idt.c
+++ kernel/idt.c
#include "kdebug.h"
#include "types.h"
+#define APIC_EOI_REG ((volatile u32*)0xFEE000B0)
+
struct idt_desc {
u16 offset_1;
u16 selector;
u64 base;
} __packed;
-static struct idt_desc desc[32];
+static struct idt_desc desc[256];
void debug_exception_handler(void);
void page_fault_handler(void);
void double_fault_handler(void);
void general_protection_handler(void);
+void timer_handler(void);
void load_idt(struct idt_ptr *); /* set lidt.s */
desc[14].offset_3 = (u32)(((u64)(page_fault_handler) >> 32));
desc[14].zero = 0;
+ // TIMER INTERRUPT (custom)
+ desc[0x20].offset_1 = (u16)((u64)(timer_handler) & 0xffff);
+ desc[0x20].selector = 0x08;
+ desc[0x20].ist = 0;
+ desc[0x20].type_attributes = 0x8E;
+ desc[0x20].offset_2 = (u16)(((u64)(timer_handler) & 0xffff0000) >> 16);
+ desc[0x20].offset_3 = (u32)(((u64)(timer_handler) >> 32));
+ desc[0x20].zero = 0;
+
load_idt(&ptr);
return 0;
{
kprint("#GP interrupt\n");
}
+
+u64 tint = 0;
+
+void
+timer_handler_c()
+{
+ kprint("Timer interrupt: "); kprinti(tint++); kprint("\n");
+
+ *APIC_EOI_REG = 0; // Tells register interrupt was received
+}
blob - 088c815aa876b54b6d2a83a4386af126be315d9e
blob + 5ebcf6e1480e25bb0cbe91bb902bdc7fb8c72303
--- kernel/kmain.c
+++ kernel/kmain.c
static void kloop(struct module *, struct mmap *);
void
-kmain(struct kinfo *kinfo)
+kmain(struct kinfo *kinfo, u8 drive)
{
struct mmap *ammap;
kprint("Only 10 remote holes in a heck of a long time!\n");
kprint("GDT configured!\n");
- kpic_setup();
syscalls_init();
if (idt_init() == -1) {
return;
}
+ kpic_setup();
+
kprint("Page tables configured!\n");
kprint("Free memory U/S bit set!\n");
kloop(&kinfo->modules[1], ammap);
}
-// Defined in switch.s
-void start_alpha(struct mmap *ammap, struct thread *thread);
-void switch_context(struct thread *old, struct thread *new);
-
static void
kloop(struct module *amodule, struct mmap *ammap)
{
if (athread == nil) {
kprint("Failed to create thread\n");
- goto repeat;
+ repeat: goto repeat;
}
- kprint("Jumping to alpha!\n");
- start_alpha(ammap, athread);
- repeat: goto repeat;
+ thread_schedule(ammap, athread);
}
blob - 51f6b639c87130e8f972813419c6eddbccfa9829
blob + 3334258cf25f3e68aae8d615009bfc9bba95d272
--- kernel/kmmap.c
+++ kernel/kmmap.c
struct module *kmodule = &kinfo->modules[0];
struct module *amodule = &kinfo->modules[1];
+ struct module *xhci_module = &kinfo->modules[2];
+ u64 nmodules = sizeof(kinfo->modules) / sizeof(*kinfo->modules);
u64 memsize = 0;
for (u64 i = 0; i < kinfo->e820_bcount; i++) {
for (u64 i = 0; i < kmodule->entry + kmodule->size; i += PAGE_SIZE)
set_bitmap(i);
- // Alpha module is occupied
+ // Occupy other modules
- for (u64 i = amodule->entry; i < amodule->entry + amodule->size; i += PAGE_SIZE)
- set_bitmap(i);
+ for (u64 i = 1; i < nmodules; i++) {
+ struct module *m = &kinfo->modules[i];
+ for (u64 j = m->entry; j < m->entry + m->size; j += PAGE_SIZE)
+ set_bitmap(j);
+ }
PageTableCount = kminfo.frames;
PageDirCount = (PageTableCount + P_ENTRIES - 1) / P_ENTRIES;
if (kminfo.amap == nil)
return nil;
- // Changing amodule to user
+ // Changing modules to user mode
- for (u64 i = amodule->entry; i < amodule->entry + amodule->size; i += PAGE_SIZE)
- kmmap_addr_touser(i);
+ for (u64 i = 1; i < nmodules; i++) {
+ struct module *m = &kinfo->modules[i];
+ for (u64 j = m->entry; j < m->entry + m->size; j += PAGE_SIZE)
+ kmmap_addr_touser(j);
+ }
+
kmmap_usermode();
return kminfo.amap;
blob - 5275b82f081415d89d7f8233b0b66fc381ddc828
blob + 22b22d08c60f36ee2e5a4ddf1e2557d122dde1f1
--- kernel/kmmap.h
+++ kernel/kmmap.h
};
struct kinfo {
- struct module modules[2];
+ struct module modules[3];
u64 e820_bcount;
struct e820h *e820_headers;
};
blob - 23604f521342f4d853c24fc4cbe9630ac1979487
blob + 5b711f5a26c269a6ec68fd7615236c460ef62d09
--- kernel/kpic.c
+++ kernel/kpic.c
#include "types.h"
#include "kdebug.h"
+#define APIC_TIMER_CUR ((u32 *)0xFEE00390)
+#define APIC_TIMER_INI ((u32 *)0xFEE00380)
+#define APIC_TIMER_DIV ((u32 *)0xFEE003E0)
+#define APIC_TIMER_LVT ((u32 *)0xFEE00320)
+
+#define APIC_LVT_PERIODIC 0x20000
+#define TIMER_VECTOR 0x20
+
+#define IA32_APIC_BASE_MSR 0x1B
+#define IA32_APIC_BASE_MSR_ENABLE 0x800
+
#define PIC1 0x20
#define PIC2 0xA0
#define PIC1_DATA (PIC1+1)
#define PIC2_DATA (PIC2+1)
-void
-kpic_setup()
+// See sysentry.s
+u64 rdmsr(u32 msr);
+void wrmsr(u32 msr, u64 value);
+
+static void apic_setup_timer(void);
+
+static void
+pic_disable()
{
outb(PIC1_DATA, 0xff);
outb(PIC2_DATA, 0xff);
}
+
+// Enable local APIC for a core
+
+void
+kpic_setup()
+{
+ u64 apic_base;
+ u32 *spivptr;
+ u32 spiv;
+
+ pic_disable();
+
+ // Enable local APIC
+
+ apic_base = rdmsr(IA32_APIC_BASE_MSR);
+
+ apic_base |= IA32_APIC_BASE_MSR_ENABLE;
+
+ wrmsr(IA32_APIC_BASE_MSR, apic_base);
+
+ // Start receiving interrupts
+
+ spivptr = (u32 *)0xFEE000F0;
+ spiv = *spivptr;
+
+ spiv |= 0x100;
+ spiv |= 0xFF;
+
+ *spivptr = spiv;
+
+ apic_setup_timer();
+}
+
+static void
+apic_setup_timer()
+{
+ // Clock divider
+ *APIC_TIMER_DIV = 0x03;
+
+ // Setup register
+ *APIC_TIMER_LVT = APIC_LVT_PERIODIC | TIMER_VECTOR;
+
+ // Initial countdown
+ *APIC_TIMER_INI = 10000000;
+}
blob - ad5151966c615d05cc3610d39e1438f46e7e5c1d
blob + 2accf334df9298693dd6ee50980ab5275610c0a0
--- kernel/kthreads.c
+++ kernel/kthreads.c
#define MAX_USER_THREADS 64
static struct thread uthreads[MAX_USER_THREADS];
+static struct thread *cthread;
struct thread*
thread_create(void (*entry)(void))
return nil;
}
- kprint("Creating thread\n");
thread->base = allocate_memory(PAGE_SIZE);
if (thread->base == nil) {
return thread;
}
+
+s64
+thread_getuid(struct thread *th)
+{
+ for (int i = 0; i < MAX_USER_THREADS; i++) {
+ if (&uthreads[i] == th)
+ return i;
+ }
+
+ return -1;
+}
+
+// This is defined in switch.s
+
+void start_alpha(struct mmap *ammap, struct thread *thread);
+void switch_context(struct thread *old, struct thread *new);
+
+void
+thread_schedule(struct mmap *ammap, struct thread *th)
+{
+ cthread = th;
+ start_alpha(ammap, th);
+
+ repeat: goto repeat;
+}
+
+void
+thread_switch(struct thread *th)
+{
+ struct thread *othread;
+
+ if (th == cthread) {
+ kprint("Huh?\n");
+ return;
+ }
+
+ othread = cthread;
+ cthread = th;
+ switch_context(othread, cthread);
+}
+
+struct thread*
+thread_get_uthread(u64 id)
+{
+ if (id < MAX_USER_THREADS && uthreads[id].assigned == 1)
+ return &uthreads[id];
+ return nil;
+}
blob - 911e2269adde81f02054325a01a8d4f4c36b56a3
blob + b962ab43fc5883d0f878a41c640fde2977e15761
--- kernel/kthreads.h
+++ kernel/kthreads.h
#pragma once
+#include "kmmap.h"
+
+enum thread_state {
+ THREAD_READY,
+ THREAD_RUNNING,
+};
+
struct thread {
u64 *base;
u64 *top;
u64 rsp;
+
u8 assigned;
+ enum thread_state sate;
};
struct thread *thread_create(void (*entry)(void));
+s64 thread_getuid(struct thread *th);
+void thread_schedule(struct mmap *, struct thread *);
+void thread_switch(struct thread *);
+struct thread *thread_get_uthread(u64 id);
blob - 956758d0e646b87b571b9d62ab69efe230287cfb
blob + 086afdfc65590671baca91ac1a342feeec475041
--- kernel/lidt.s
+++ kernel/lidt.s
global general_protection_handler
extern general_protection_handler_c
+global timer_handler
+extern timer_handler_c
+
load_idt:
lidt [rdi]
ret
general_protection_handler:
call general_protection_handler_c
hlt
+
+timer_handler:
+ call timer_handler_c
+ iretq
blob - 96cdf2ec8e0f43812f162b177f0270aa9aa8fb4a
blob + 97983d5a50a7c11a00eb9b8167610e5a3babe57c
--- kernel/syscalls.c
+++ kernel/syscalls.c
#include "types.h"
#include "kdebug.h"
+#include "kthreads.h"
#include "syscalls/syscalls.h"
#define IA32_EFER 0xC0000080
}
void
+syscall_new_thread_h(struct sysc_new_thread *nthread)
+{
+ struct thread *th = thread_create(nthread->entry);
+ s64 threadid;
+
+ if (th == nil)
+ kprint("failed to create thread from syscall!\n");
+
+ threadid = thread_getuid(th);
+ nthread->retid = threadid;
+
+ kprint("Thread (id="); kprinti(threadid); kprint(") created!\n");
+}
+
+void
+syscall_context_switch_h(struct sysc_context_switch *scs)
+{
+ struct thread *cthread = thread_get_uthread(scs->threadid);
+
+ if (cthread == nil) {
+ kprint("No current thread :/\n");
+ return;
+ }
+
+ thread_switch(cthread);
+}
+
+void
syscall_handler(struct sysc *call)
{
switch (call->type) {
case SYSC_ECHO:
syscall_echo_h((struct sysc_echo *)call);
break;
+ case SYSC_NEW_THREAD:
+ syscall_new_thread_h((struct sysc_new_thread *)call);
+ break;
+ case SYSC_CONTEXT_SWITCH:
+ syscall_context_switch_h((struct sysc_context_switch *)call);
+ break;
default:
break;
}
blob - 3d5477f9fc4ebb1e5081b30b5d0558fc90973efc
blob + a63060857332e965651f8484c979a5233d2346eb
--- servers/xhci/main.c
+++ servers/xhci/main.c
#include "types.h"
#include "syscalls/syscalls.h"
+static void send_msg (const u8 *msg);
+
void
xhci_main()
{
+ send_msg("xhci: driver started\n");
+
for (;;);
}
+
+static void
+send_msg (const u8 *msg)
+{
+ struct sysc_echo echo;
+ echo.sysc.type = SYSC_ECHO;
+ echo.msg = msg;
+ sys_send((struct sysc *)&echo);
+}
+
blob - f4d21d3b8483f50020a2d4112286b187c1cd34d5
blob + 4ed19f7d29b986549d6fec7d04fe784cbd0226cc
--- syscalls/syscalls.h
+++ syscalls/syscalls.h
enum sysc_type {
SYSC_ECHO,
+ SYSC_NEW_THREAD,
+ SYSC_FREE_THREAD,
+ SYSC_CONTEXT_SWITCH, // This shouldn't be a thing its for testing before APIC and thread states
};
struct sysc {
const char *msg;
};
+struct sysc_new_thread {
+ struct sysc sysc;
+ void *entry;
+ u64 size; // Unused for now
+
+ s64 retid; // The threadId returned
+};
+
+struct sysc_free_thread {
+ struct sysc sysc;
+ u64 id;
+};
+
+struct sysc_context_switch {
+ struct sysc sysc;
+ u64 threadid;
+};
+
void sys_send(struct sysc *);
void sys_recv(void);