diff --git a/Makefile b/Makefile index 9a234e2..6489355 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ LD = $(CROSS)ld OBJCOPY = $(CROSS)objcopy OBJDUMP = $(CROSS)objdump -kernel_sources = interrupts.cc panic.cc data.cc test.cc alloc.cc memory.cc +kernel_sources = interrupts.cc panic.cc data.cc test.cc alloc.cc memory.cc arch.cc invoke.cc schedule.cc boot_sources = init.cc BUILT_SOURCES = $(kernel_sources) $(boot_sources) @@ -22,7 +22,7 @@ PYPP = /usr/bin/pypp uimage: all.raw Makefile mkimage -A MIPS -O Linux -C none -a $(load) -e 0x$(shell /bin/sh -c '$(OBJDUMP) -t all | grep __start$$ | cut -b-8') -n "Shevek's kernel" -d $< $@ | sed -e 's/:/;/g' -arch.hh: mips.hh +arch.%: mips.% ln -s $< $@ || true %.o:%.cc Makefile kernel.hh arch.hh diff --git a/alloc.ccp b/alloc.ccp index 7cb81eb..310c177 100644 --- a/alloc.ccp +++ b/alloc.ccp @@ -1,6 +1,7 @@ #pypp 0 #include "kernel.hh" +// TODO: avoid recursion. bool Memory::use (): if used >= limit: return false @@ -143,6 +144,34 @@ Thread *Memory::alloc_thread (): ret->schedule_next = NULL return ret +Message *Memory::alloc_message (Capability *source): + Message *ret = (Message *)search_free (sizeof (Message), (void **)&source->target->messages) + for unsigned i = 0; i < 4; ++i: + ret->capabilities[i] = NULL + ret->data[i] = 0 + ret->protected_data = source->protected_data + return ret + +Receiver *Memory::alloc_receiver (): + Receiver *ret = (Receiver *)search_free (sizeof (Receiver), (void **)&receivers) + ret->owner = NULL + ret->prev_owned = NULL + ret->next_owned = NULL + ret->capabilities = NULL + ret->messages = NULL + return ret + +Capability *Memory::alloc_capability (Receiver *target, Capability **parent, unsigned protected_data): + Capability *ret = (Capability *)search_free (sizeof (Capability), (void **)&capabilities) + ret->target = target + ret->children = NULL + ret->sibling_prev = NULL + ret->sibling_next = parent ? *parent : NULL + if ret->sibling_next: + ret->sibling_next->sibling_prev = ret + ret->protected_data = protected_data + return ret + Memory *Memory::alloc_memory (): Memory *ret = (Memory *)search_free (sizeof (Memory), (void **)&memories) ret->parent = this @@ -164,7 +193,7 @@ void Memory::free_page (Page *page): page->next->prev = page->prev unuse () pfree (page->physical) - free_obj (this) + page->free_obj (this) void Memory::free_thread (Thread *thread): if thread->prev: @@ -173,8 +202,82 @@ void Memory::free_thread (Thread *thread): threads = thread->next if thread->next: thread->next->prev = thread->prev - // TODO: unschedule - free_obj (this) + // Unschedule. + if thread->schedule_prev: + thread->schedule_prev->schedule_next = thread->schedule_next + else if first_scheduled == thread: + first_scheduled = thread->schedule_next + if thread->schedule_next: + thread->schedule_next->schedule_prev = thread->schedule_prev + thread->free_obj (this) + +void Memory::free_message (Message *message): + for unsigned i = 0; i < 4; ++i: + free_capability (message->capabilities[i]) + message->free_obj (this) + +void Memory::free_receiver (Receiver *receiver): + if receiver->prev_owned: + receiver->prev_owned->next_owned = receiver->next_owned + else: + receiver->owner->receivers = receiver->next_owned + if receiver->next_owned: + receiver->next_owned->prev_owned = receiver->prev_owned + while receiver->capabilities: + receiver->capabilities->invalidate () + while receiver->messages: + free_message (receiver->messages) + receiver->free_obj (this) + +void Memory::free_capability (Capability *capability): + if capability->sibling_prev: + capability->sibling_prev->sibling_next = capability->sibling_next + else: + capability->target->capabilities = capability->sibling_next + if capability->sibling_next: + capability->sibling_next->sibling_prev = capability->sibling_prev + // The sibling_prev link is used here to point to the parent. + // This method is used to avoid recursion. + capability->sibling_prev = NULL + Capability *c = capability + while c->children: + c->children->sibling_prev = c + c = c->children + while c: + Capability *next = c->sibling_next + if !next: + next = c->sibling_prev + if next: + next->sibling_prev = c->sibling_prev + c->free_obj (this) + c = next + +void Capability::invalidate (): + if sibling_prev: + sibling_prev->sibling_next = sibling_next + else: + target->capabilities = sibling_next + if sibling_next: + sibling_next->sibling_prev = sibling_prev + // The sibling_prev link is used here to point to the parent. + // This method is used to avoid recursion. + sibling_prev = NULL + Capability *c = this + while c->children: + c->children->sibling_prev = c + c = c->children + while c: + Capability *next = c->sibling_next + if !next: + next = c->sibling_prev + if next: + next->sibling_prev = c->sibling_prev + c->target = NULL + c->children = NULL + c->sibling_prev = NULL + c->sibling_next = NULL + c->protected_data = 0 + c = next void Memory::free_memory (Memory *mem): if mem->prev: @@ -190,4 +293,4 @@ void Memory::free_memory (Memory *mem): while mem->memories: free_memory (mem->memories) Memory_arch_free (mem) - free_obj (this) + mem->free_obj (this) diff --git a/entry.S b/entry.S index 5c9bae7..3700cb7 100644 --- a/entry.S +++ b/entry.S @@ -72,13 +72,6 @@ addr_100: .fill 0x180 - (. - addr_000) addr_180: // General exception - // TODO - - li $a0, 0xaaff0000 - la $t9, panic - jr $t9 - nop - sw $ra, -0x188($zero) bal save_regs la $t9, exception diff --git a/init.ccp b/init.ccp index bf7b4e5..ba8a2f1 100644 --- a/init.ccp +++ b/init.ccp @@ -41,7 +41,7 @@ static void init_idle (): idle_memory.memories = NULL idle_memory.limit = 0 idle_memory.used = 0 - idle_memory.arch.directory = (Page ***)0x80000000 + idle_memory.arch.directory = (unsigned **)0x80000000 idle_memory.arch.asid = 0 // initialize idle_page idle_page.prev_obj = NULL diff --git a/interrupts.ccp b/interrupts.ccp index 91b7875..28d0b00 100644 --- a/interrupts.ccp +++ b/interrupts.ccp @@ -1,23 +1,11 @@ #pypp 0 #include "kernel.hh" -// hi and lo cannot be saved in assemply due to space restrictions. -#define save_hilo(x) do { __asm__ volatile ("mfhi %0 ; mflo %1" : "=r"((x)->arch.hi), "=r"((x)->arch.lo)); } while (0) - /// A TLB miss has occurred. This should eventually move to entry.S. Thread *tlb_refill (Thread *current, unsigned EntryHi): - save_hilo (current) - Page ***dir = current->address_space->arch.directory - if !dir: - panic (0x00000000, "no page directory for thread") - EntryHi >>= 12 - Page **table = dir[EntryHi >> 10] - if !table: - panic (0x11111111, "no page table at requested address") - EntryHi &= (1 << 10) - 1 - Page *page0 = table[EntryHi & ~1] - Page *page1 = table[EntryHi | 1] - if (!(EntryHi & 1) && !page0) || ((EntryHi & 1) && !page1): + Page *page0 = current->address_space->get_mapping (EntryHi & ~(1 << 12)) + Page *page1 = current->address_space->get_mapping (EntryHi | (1 << 12)) + if (!(EntryHi & (1 << 12)) && !page0) || ((EntryHi & (1 << 12)) && !page1): panic (0x22222222, "no page mapped at requested address") unsigned low0, low1 if page0: @@ -33,17 +21,98 @@ Thread *tlb_refill (Thread *current, unsigned EntryHi): /// An interrupt which is not an exception has occurred. Thread *interrupt (Thread *current): - save_hilo (current) + unsigned cause + __asm__ volatile ("mfc0 %0, $13" : "=r"(cause)) + for unsigned i = 0; i < 8; ++i: + if cause & (1 << (i + 8)): + // TODO: Handle interrupt. + // Disable all interrupts which are not handled. + unsigned status + __asm__ volatile ("mfc0 %0, $12" : "=r"(status)) + __asm__ volatile ("mfc0 %0, $13" : "=r"(cause)) + status &= ~(cause & 0x0000ff00) + __asm__ volatile ("mtc0 %0, $12" :: "r"(status)) return current /// A general exception has occurred. Thread *exception (Thread *current): - save_hilo (current) - panic (0xdeadbeaf, "exception") + unsigned cause + __asm__ volatile ("mfc0 %0, $13" : "=r"(cause)) + switch (cause >> 2) & 0x1f: + case 0: + // Interrupt. + panic (0x11223344, "Interrupt.") + case 1: + // TLB modification. + panic (0x11223344, "TLB modification.") + case 2: + // TLB load or instruction fetch. + panic (0x11223344, "TLB load or instruction fetch.") + case 3: + // TLB store. + panic (0x11223344, "TLB store.") + case 4: + // Address error load or instruction fetch. + panic (0x11223344, "Address error load or instruction fetch.") + case 5: + // Address error store. + panic (0x11223344, "Address error store.") + case 6: + // Bus error instruction fetch. + panic (0x11223344, "Bus error instruction fetch.") + case 7: + // Bus error load or store. + panic (0x11223344, "Bus error load or store.") + case 8: + // Syscall. + Thread_arch_invoke () + return current + case 9: + // Breakpoint. + panic (0x11223344, "Breakpoint.") + case 10: + // Reserved instruction. + panic (0x11223344, "Reserved instruction.") + case 11: + // Coprocessor unusable. + panic (0x11223344, "Coprocessor unusable.") + case 12: + // Arithmetic overflow. + panic (0x11223344, "Arithmetic overflow.") + case 13: + // Trap. + panic (0x11223344, "Trap.") + case 15: + // Floating point exception. + panic (0x11223344, "Floating point exception.") + case 23: + // Reference to WatchHi/WatchLo address. + panic (0x11223344, "Reference to WatchHi/WatchLo address.") + case 24: + // Machine check. + panic (0x11223344, "Machine check.") + case 30: + // Cache error (EJTAG only). + panic (0x11223344, "Cache error (EJTAG only).") + case 14: + case 16: + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 25: + case 26: + case 27: + case 28: + case 29: + case 31: + // Reserved. + panic (0x11223344, "Reserved.") return current /// There's a cache error. Big trouble. Probably not worth trying to recover. Thread *cache_error (Thread *current): - save_hilo (current) panic (0x33333333, "cache error") return current diff --git a/invoke.ccp b/invoke.ccp new file mode 100644 index 0000000..75abd0e --- /dev/null +++ b/invoke.ccp @@ -0,0 +1,14 @@ +#pypp 0 +#include "kernel.hh" + +Capability *Memory::find_capability (unsigned code): + for Capability *c = capabilities; c; c = c->next: + if c == (Capability *)code: + return c + return NULL + +void Capability::invoke (unsigned d0, unsigned d1, unsigned d2, unsigned d3, Capability *c0, Capability *c1, Capability *c2, Capability *c3): + if (unsigned)target & PAGE_MASK: + // TODO: Create message in receiver. + return + // TODO: Handle kernel request. diff --git a/kernel.hhp b/kernel.hhp index 0f809b3..14ef4b6 100644 --- a/kernel.hhp +++ b/kernel.hhp @@ -11,6 +11,9 @@ struct Object_base struct Page struct Thread +struct Message +struct Receiver +struct Capability struct Memory #include "arch.hh" @@ -42,18 +45,41 @@ struct Thread : public Object : unsigned pc, sp Thread_arch arch Thread *schedule_prev, *schedule_next + Receiver *receivers + +struct Message : public Object : + Capability *capabilities[4] + unsigned data[4] + unsigned protected_data + +struct Receiver : public Object : + Thread *owner + Receiver *prev_owned, *next_owned + Capability *capabilities + Message *messages + +struct Capability : public Object : + Receiver *target + Capability *children + Capability *sibling_prev, *sibling_next + unsigned protected_data + void invoke (unsigned d0, unsigned d1, unsigned d2, unsigned d3, Capability *c0, Capability *c1, Capability *c2, Capability *c3) + void invalidate () struct Memory : public Object : Memory *parent Free *frees Page *pages Thread *threads + Receiver *receivers + Capability *capabilities Memory *memories unsigned limit, used Memory_arch arch - void unmap (Page *page, void *address): - Memory_arch_unmap (this, page, address) + inline bool map (Page *page, unsigned address, bool write) + inline void unmap (Page *page, unsigned address) + inline Page *get_mapping (unsigned address) // Allocation of pages. bool use () @@ -67,14 +93,19 @@ struct Memory : public Object : void *search_free (unsigned size, void **first) Page *alloc_page () Thread *alloc_thread () + Message *alloc_message (Capability *source) + Receiver *alloc_receiver () + Capability *alloc_capability (Receiver *target, Capability **parent, unsigned protected_data) Memory *alloc_memory () void free_page (Page *page) void free_thread (Thread *thread) + void free_message (Message *message) + void free_receiver (Receiver *receiver) + void free_capability (Capability *capability) void free_memory (Memory *mem) -#define ARCH_PART2 -#include "arch.hh" + Capability *find_capability (unsigned code) // Functions which can be called from assembly must not be mangled. extern "C": @@ -83,6 +114,8 @@ extern "C": // Debug: switch caps led void led (bool one, bool two, bool three) +void schedule () + struct FreePage: FreePage *next @@ -92,5 +125,23 @@ EXTERN Thread *sleepers, *runners EXTERN Thread idle EXTERN Memory idle_memory EXTERN Page idle_page +EXTERN Thread *first_scheduled +EXTERN Thread *current + +// Defined in arch.cc +void Thread_arch_init (Thread *thread) +void Thread_arch_invoke () +void Memory_arch_init (Memory *mem) +void Memory_arch_free (Memory *mem) +bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write) +void Memory_arch_unmap (Memory *mem, Page *page, unsigned address) +Page *Memory_arch_get_mapping (Memory *mem, unsigned address) + +bool Memory::map (Page *page, unsigned address, bool write): + return Memory_arch_map (this, page, address, write) +void Memory::unmap (Page *page, unsigned address): + Memory_arch_unmap (this, page, address) +Page *Memory::get_mapping (unsigned address): + return Memory_arch_get_mapping (this, address) #endif diff --git a/mips.ccp b/mips.ccp new file mode 100644 index 0000000..541941d --- /dev/null +++ b/mips.ccp @@ -0,0 +1,88 @@ +#pypp 0 +#include "kernel.hh" + +void Thread_arch_init (Thread *thread): + thread->arch.at = 0 + thread->arch.v0 = 0 + thread->arch.v1 = 0 + thread->arch.a0 = 0 + thread->arch.a1 = 0 + thread->arch.a2 = 0 + thread->arch.a3 = 0 + thread->arch.t0 = 0 + thread->arch.t1 = 0 + thread->arch.t2 = 0 + thread->arch.t3 = 0 + thread->arch.t4 = 0 + thread->arch.t5 = 0 + thread->arch.t6 = 0 + thread->arch.t7 = 0 + thread->arch.t8 = 0 + thread->arch.t9 = 0 + thread->arch.gp = 0 + thread->arch.fp = 0 + thread->arch.ra = 0 + thread->arch.hi = 0 + thread->arch.lo = 0 + thread->arch.k0 = 0 + thread->arch.k1 = 0 + +void Memory_arch_init (Memory *mem): + ++g_asid + g_asid &= 0x3f + if !g_asid: + ++g_asid + mem->arch.asid = g_asid + mem->arch.directory = NULL + +void Memory_arch_free (Memory *mem): + if !mem->arch.directory: + return + for unsigned i = 0; i < PAGE_SIZE; ++i: + unsigned *table = mem->arch.directory[i] + if !table: + continue + for unsigned j = 0; j < PAGE_SIZE; ++j: + Page *page = (Page *)(table[j] & ~3) + if !page: + continue + mem->unmap (page, i * 0x1000 * 0x400 + j * 0x1000) + mem->unuse () + mem->zfree (table) + mem->arch.directory[i] = NULL + mem->unuse () + mem->zfree (mem->arch.directory) + +bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write): + unsigned *table = mem->arch.directory[(unsigned)address >> 22] + if !table: + table = (unsigned *)mem->zalloc () + if !table: + return false + mem->arch.directory[(unsigned)address >> 22] = table + unsigned idx = ((unsigned)address >> 12) & ((1 << 10) - 1) + if table[idx]: + mem->unmap ((Page *)(table[idx] & ~3), address) + table[idx] = write ? (unsigned)page : (unsigned)page + 1 + +void Memory_arch_unmap (Memory *mem, Page *page, unsigned address): + unsigned *table = mem->arch.directory[(unsigned)address >> 22] + table[((unsigned)address >> 12) & ((1 << 10) - 1)] = 0 + +Page *Memory_arch_get_mapping (Memory *mem, unsigned address): + unsigned *table = mem->arch.directory[(unsigned)address >> 22] + unsigned v = table[((unsigned)address >> 12) & ((1 << 10) - 1)] + +void Thread_arch_invoke (): + Capability *target, *c0, *c1, *c2, *c3 + target = current->address_space->find_capability (current->arch.v0) + if !target: + // TODO: there must be no action here. This is just because the rest doesn't work yet. + led (current->arch.a0, current->arch.a1, current->arch.a2) + schedule () + return + c0 = current->address_space->find_capability (current->arch.a0) + c1 = current->address_space->find_capability (current->arch.a1) + c2 = current->address_space->find_capability (current->arch.a2) + c3 = current->address_space->find_capability (current->arch.a3) + target->invoke (current->arch.t0, current->arch.t1, current->arch.t2, current->arch.t3, c0, c1, c2, c3) diff --git a/mips.hhp b/mips.hhp index 274358b..2866fb7 100644 --- a/mips.hhp +++ b/mips.hhp @@ -13,69 +13,10 @@ struct Thread_arch: struct Memory_arch: unsigned asid - Page ***directory - -static void Memory_arch_unmap (Memory *mem, Page *page, void *address) - -#endif // _ARCH_HH - -#ifdef ARCH_PART2 -static void Thread_arch_init (Thread *thread): - thread->arch.at = 0 - thread->arch.v0 = 0 - thread->arch.v1 = 0 - thread->arch.a0 = 0 - thread->arch.a1 = 0 - thread->arch.a2 = 0 - thread->arch.a3 = 0 - thread->arch.t0 = 0 - thread->arch.t1 = 0 - thread->arch.t2 = 0 - thread->arch.t3 = 0 - thread->arch.t4 = 0 - thread->arch.t5 = 0 - thread->arch.t6 = 0 - thread->arch.t7 = 0 - thread->arch.t8 = 0 - thread->arch.t9 = 0 - thread->arch.gp = 0 - thread->arch.fp = 0 - thread->arch.ra = 0 - thread->arch.hi = 0 - thread->arch.lo = 0 - thread->arch.k0 = 0 - thread->arch.k1 = 0 + unsigned **directory EXTERN unsigned g_asid -static void Memory_arch_init (Memory *mem): - ++g_asid - g_asid &= 0x3f - if !g_asid: - ++g_asid - mem->arch.asid = g_asid - mem->arch.directory = NULL - -static void Memory_arch_free (Memory *mem): - if !mem->arch.directory: - return - for unsigned i = 0; i < PAGE_SIZE; ++i: - Page **table = mem->arch.directory[i] - if !table: - continue - for unsigned j = 0; j < PAGE_SIZE; ++j: - Page *page = table[j] - if !page: - continue - mem->unmap (page, (void *)(i * 0x1000 * 0x400 + j * 0x1000)) - mem->unuse () - mem->zfree (table) - mem->arch.directory[i] = NULL - mem->unuse () - mem->zfree (mem->arch.directory) - -static void Memory_arch_unmap (Memory *mem, Page *page, void *address): - // Functions which can be called from assembly must not be mangled. extern "C": // Kernel entry points, called from entry.S. @@ -91,4 +32,4 @@ extern "C": void run_idle (Thread *self) #endif -#endif // ARCH_PART2 +#endif diff --git a/schedule.ccp b/schedule.ccp new file mode 100644 index 0000000..b51e525 --- /dev/null +++ b/schedule.ccp @@ -0,0 +1,10 @@ +#pypp 0 +#include "kernel.hh" + +void schedule (): + if current: + current = current->schedule_next + if !current: + current = first_scheduled + if !current: + current = &idle