mirror of
git://projects.qi-hardware.com/iris.git
synced 2024-11-04 23:08:26 +02:00
start with allocation
This commit is contained in:
parent
5d9d12b860
commit
e56cf6bb64
9
Makefile
9
Makefile
@ -8,7 +8,7 @@ LD = $(CROSS)ld
|
||||
OBJCOPY = $(CROSS)objcopy
|
||||
OBJDUMP = $(CROSS)objdump
|
||||
|
||||
kernel_sources = interrupts.cc panic.cc data.cc test.cc
|
||||
kernel_sources = interrupts.cc panic.cc data.cc test.cc alloc.cc
|
||||
boot_sources = init.cc
|
||||
BUILT_SOURCES = $(kernel_sources) $(boot_sources)
|
||||
|
||||
@ -22,7 +22,10 @@ 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'
|
||||
|
||||
%.o:%.cc Makefile kernel.hh
|
||||
arch.hh: mips.hh
|
||||
ln -s $< $@
|
||||
|
||||
%.o:%.cc Makefile kernel.hh arch.hh
|
||||
$(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
%.o:%.S Makefile
|
||||
@ -40,6 +43,6 @@ junk = mdebug.abi32 reginfo comment pdr
|
||||
gzip < $< > $@
|
||||
|
||||
clean:
|
||||
rm -f all uimage *.o all.raw.gz
|
||||
rm -f all uimage *.o all.raw.gz arch.hh
|
||||
|
||||
.PHONY: clean
|
||||
|
142
alloc.ccp
Normal file
142
alloc.ccp
Normal file
@ -0,0 +1,142 @@
|
||||
#include "kernel.hh"
|
||||
|
||||
void *Memory::palloc ():
|
||||
if use >= limit:
|
||||
return NULL
|
||||
FreePage *ret = junk_pages
|
||||
if !ret:
|
||||
ret = zero_pages
|
||||
zero_pages = ret->next
|
||||
else:
|
||||
junk_pages = ret->next
|
||||
return ret
|
||||
|
||||
void *Memory::zalloc ():
|
||||
if use >= limit:
|
||||
return NULL
|
||||
FreePage *ret = zero_pages
|
||||
if !ret:
|
||||
ret = junk_pages
|
||||
for unsigned i = 1; i < PAGE_SIZE; ++i:
|
||||
((unsigned *)ret)[i] = 0
|
||||
junk_pages = ret->next
|
||||
else:
|
||||
zero_pages = ret->next
|
||||
ret->next = NULL
|
||||
return ret
|
||||
|
||||
void Memory::pfree (void *page):
|
||||
FreePage *p = (FreePage *)page
|
||||
p->next = junk_pages
|
||||
junk_pages = p
|
||||
|
||||
void Memory::zfree (void *page):
|
||||
FreePage *p = (FreePage *)page
|
||||
p->next = zero_pages
|
||||
zero_pages = p
|
||||
|
||||
void *Memory::search_free (unsigned size, void *&first):
|
||||
Free *f
|
||||
unsigned s = 0
|
||||
for f = frees; f; f = f->next:
|
||||
if f->next_obj:
|
||||
s = f->next_obj - f
|
||||
else:
|
||||
s = PAGE_SIZE - ((unsigned)f & ~PAGE_MASK)
|
||||
if s >= size:
|
||||
break
|
||||
if !f:
|
||||
f = (Free *)palloc ()
|
||||
if !f:
|
||||
return NULL
|
||||
f->marker = ~0
|
||||
f->next = frees
|
||||
f->prev = NULL
|
||||
frees = f
|
||||
if f->next:
|
||||
f->next->prev = f
|
||||
f->next_obj = NULL
|
||||
f->prev_obj = NULL
|
||||
s = PAGE_SIZE
|
||||
// We have a free block, possibly too large.
|
||||
if s >= size + sizeof (Free):
|
||||
// Create the new object at the end and keep the Free.
|
||||
Free *obj = (Free *)((unsigned)f + s - size)
|
||||
obj->next_obj = f->next_obj
|
||||
if (obj->next_obj)
|
||||
obj->next_obj->prev_obj = obj
|
||||
obj->prev_obj = f
|
||||
f->next_obj = obj
|
||||
f = obj
|
||||
else:
|
||||
if f->prev:
|
||||
f->prev->next = f->next
|
||||
else:
|
||||
frees = f->next
|
||||
if f->next:
|
||||
f->next->prev = f->prev
|
||||
f->next = first
|
||||
f->prev = NULL
|
||||
if f->next:
|
||||
f->next->prev = f
|
||||
first = f
|
||||
return f
|
||||
|
||||
void Object_base::free_obj (Memory *parent):
|
||||
Free *self
|
||||
// Merge with previous, if it exists and is a Free.
|
||||
if prev_obj && prev_obj->is_free ():
|
||||
self = (Free *)prev_obj
|
||||
self->next_obj = next_obj
|
||||
if next_obj:
|
||||
next_obj->prev_obj = self
|
||||
else:
|
||||
self = (Free *)this
|
||||
self->next = parent->frees
|
||||
self->prev = NULL
|
||||
if self->next:
|
||||
self->next->prev = self
|
||||
parent->frees = self
|
||||
self->marker = ~0
|
||||
// Merge with next, if it exists and is a Free.
|
||||
if self->next_obj && self->next_obj->is_free ():
|
||||
self->next_obj = self->next_obj->next_obj
|
||||
if self->next_obj:
|
||||
self->next_obj->prev_obj = self
|
||||
// Free page if the resulting object is the only thing in it.
|
||||
if !self->prev_obj && !self->next_obj:
|
||||
if self->next:
|
||||
self->next->prev = self->prev
|
||||
if self->prev:
|
||||
self->prev->next = self->next
|
||||
else:
|
||||
parent->frees = self->next
|
||||
parent->pfree (self)
|
||||
|
||||
Page *Memory::alloc_page ():
|
||||
Page *ret = (Page *)search_free (sizeof (Page), pages)
|
||||
ret->physical = zalloc ()
|
||||
if !ret->physical:
|
||||
ret->free (this, pages)
|
||||
return ret
|
||||
|
||||
Thread *Memory::alloc_thread ():
|
||||
Thread *ret = (Thread *)search_free (sizeof (Thread), threads)
|
||||
ret->address_space = this
|
||||
ret->pc = 0
|
||||
ret->sp = 0
|
||||
Thread_arch_init (ret)
|
||||
ret->schedule_prev = NULL
|
||||
ret->schedule_next = NULL
|
||||
return ret
|
||||
|
||||
Memory *Memory::alloc_memory ():
|
||||
Memory *ret = (Memory *)search_free (sizeof (Memory), memories)
|
||||
ret->frees = NULL
|
||||
ret->pages = NULL
|
||||
ret->threads = NULL
|
||||
ret->memories = NULL
|
||||
ret->limit = ~0
|
||||
ret->used = 0
|
||||
Memory_arch_init (ret)
|
||||
return ret
|
82
init.ccp
82
init.ccp
@ -1,6 +1,26 @@
|
||||
#pypp 0
|
||||
// Also declare things which only work during kernel init.
|
||||
#define INIT
|
||||
#include "kernel.hh"
|
||||
|
||||
#define cp0_get(reg, sel, target) do { __asm__ volatile ("mfc0 %0, $" #reg ", " #sel : "=r (target)); } while (0)
|
||||
#define cp0_set(reg, value) do { __asm__ volatile ("mtc0 %0, $" #reg :: "r (value)); } while (0)
|
||||
#define cp0_set0(reg) do { __asm__ volatile ("mtc0 $zero, $" #reg); } while (0)
|
||||
|
||||
// cp0 registers.
|
||||
#define INDEX 0
|
||||
#define ENTRY_LO0 2
|
||||
#define ENTRY_LO1 3
|
||||
#define PAGE_MASK 5
|
||||
#define WIRED 6
|
||||
#define COUNT 9
|
||||
#define ENTRY_HI 10
|
||||
#define COMPARE 11
|
||||
#define STATUS 12
|
||||
#define CAUSE 13
|
||||
#define EPC 14
|
||||
#define CONFIG 16
|
||||
|
||||
static void init_idle ():
|
||||
// initialize idle task as if it is currently running.
|
||||
idle.size = sizeof (Thread)
|
||||
@ -34,58 +54,57 @@ static void init_idle ():
|
||||
idle_page.physical = 0
|
||||
|
||||
static void init_cp0 ():
|
||||
// Set timer to a defined value (11 is Compare)
|
||||
__asm__ volatile ("mtc0 %0, $11, 0" :: "r"(1000000))
|
||||
// Reset timer (9 is Count)
|
||||
__asm__ volatile ("mtc0 $zero, $9, 0")
|
||||
// Use the interrupt vector for interrupts (13 is Cause)
|
||||
__asm__ volatile ("mtc0 %0, $13" :: "r"(1 << 23))
|
||||
// Set timer to a defined value
|
||||
cp0_set (COMPARE, 1000000)
|
||||
// Reset timer
|
||||
cp0_set0 (COUNT)
|
||||
// Use the interrupt vector for interrupts
|
||||
cp0_set (CAUSE, 1 << 23)
|
||||
|
||||
// clear the tlb, hardwire page 0 to 0xffffffff
|
||||
// and soft-wire it to (0x294 << 20) + (0x290 << 10)
|
||||
// (for the idle task).
|
||||
|
||||
// 6 is Wired.
|
||||
__asm__ volatile ("mtc0 %0, $6" :: "r"(1))
|
||||
// 5 is PageMask.
|
||||
__asm__ volatile ("mtc0 $zero, $5")
|
||||
// 2 is EntryLo0.
|
||||
__asm__ volatile ("mtc0 $zero, $2")
|
||||
// 3 is EntryLo1.
|
||||
__asm__ volatile ("mtc0 $zero, $3")
|
||||
cp0_set (WIRED, 1)
|
||||
cp0_set0 (PAGE_MASK)
|
||||
cp0_set0 (ENTRY_LO0)
|
||||
cp0_set0 (ENTRY_LO1)
|
||||
// Get number of tlb entries (is 31).
|
||||
unsigned num;
|
||||
__asm__ volatile ("mfc0 %0, $16, 1" : "=r"(num))
|
||||
cp0_get (CONFIG, 1, num)
|
||||
num >>= 25
|
||||
num &= 0x3f
|
||||
// Clear the tlb.
|
||||
#if 0
|
||||
for unsigned i = 1; i < num; ++i:
|
||||
// this address doesn't reach the tlb, so it can't trigger exceptions.
|
||||
// 10 is EntryHi
|
||||
__asm__ volatile ("mtc0 %0, $10" :: "r"(0x70000000 + 0x1000 * i))
|
||||
// 0 is Index.
|
||||
__asm__ volatile ("mtc0 %0, $0" :: "r"(i))
|
||||
cp0_set (ENTRY_HI, 0x70000000 + 0x1000 * i)
|
||||
cp0_set (INDEX, i)
|
||||
// write the data.
|
||||
__asm__ volatile ("tlbwi")
|
||||
#endif
|
||||
// Fill the upper page in kseg3.
|
||||
__asm__ volatile ("mtc0 %0, $10" :: "r"(0xfffff000))
|
||||
__asm__ volatile ("mtc0 %0, $2" :: "r"(0x0000001d))
|
||||
__asm__ volatile ("mtc0 %0, $3" :: "r"(0x0000001f))
|
||||
__asm__ volatile ("mtc0 %0, $0" :: "r"(0))
|
||||
cp0_set (ENTRY_HI, 0xfffff000)
|
||||
cp0_set (ENTRY_LO0, 0x1d)
|
||||
cp0_set (ENTRY_LO1, 0x1f)
|
||||
cp0_set0 (INDEX)
|
||||
__asm__ volatile ("tlbwi")
|
||||
// Fill the idle task's page in useg. Set it to non-cachable.
|
||||
__asm__ volatile ("mtc0 %0, $10" :: "r"(0x284a0000))
|
||||
__asm__ volatile ("mtc0 %0, $2" :: "r"(0x00000016))
|
||||
__asm__ volatile ("mtc0 %0, $3" :: "r"(0x00000014))
|
||||
cp0_set (ENTRY_HI, 0x284a0000)
|
||||
cp0_set (ENTRY_LO0, 0x16)
|
||||
cp0_set (ENTRY_LO1, 0x14)
|
||||
__asm__ volatile ("tlbwr")
|
||||
// Allow eret to be used to jump to the idle task.
|
||||
// 14 is EPC.
|
||||
__asm__ volatile ("mtc0 %0, $14" :: "r"(0x284a0288))
|
||||
cp0_set (EPC, 0x284a0288)
|
||||
// Enable all interrupts and say we're handling an exception.
|
||||
// 12 is Status.
|
||||
__asm__ volatile ("mtc0 %0, $12" :: "r"(0x1000ff13))
|
||||
// Since we're going to enter the idle task, allow access to cp0.
|
||||
cp0_set (STATUS, 0x1000ff13)
|
||||
|
||||
static void init_threads ():
|
||||
for unsigned i = 0; i < NUM_THREADS; ++i:
|
||||
Memory *mem = top_memory.alloc_memory ()
|
||||
Thread *thread = mem->alloc_thread ()
|
||||
// TODO
|
||||
|
||||
/// Initialize the kernel, finish by falling into the idle task.
|
||||
extern unsigned _end
|
||||
@ -119,7 +138,8 @@ void init ():
|
||||
top_memory.used = 0
|
||||
top_memory.cpu.directory = NULL
|
||||
top_memory.cpu.asid = 0
|
||||
// TOOO: set up initial threads.
|
||||
|
||||
init_threads ()
|
||||
|
||||
// Done; return to user space (the idle task).
|
||||
__asm__ volatile ("eret")
|
||||
|
100
kernel.hhp
100
kernel.hhp
@ -2,66 +2,75 @@
|
||||
#ifndef _KERNEL_HH
|
||||
#define _KERNEL_HH
|
||||
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
#define NULL 0
|
||||
|
||||
class Object
|
||||
class Page
|
||||
class Thread
|
||||
class Memory
|
||||
struct Object_base
|
||||
struct Object
|
||||
struct Page
|
||||
struct Thread
|
||||
struct Memory
|
||||
|
||||
struct Object:
|
||||
unsigned size
|
||||
Object *prev, *next
|
||||
#include "arch.hh"
|
||||
|
||||
struct Page : public Object:
|
||||
Page *page_prev, *page_next
|
||||
unsigned physical
|
||||
struct Object_base:
|
||||
// Next and previous object of any type in the same page.
|
||||
Object *prev_obj, *next_obj
|
||||
void free_obj (Memory *parent)
|
||||
inline bool is_free ()
|
||||
|
||||
struct Thread : public Object:
|
||||
struct Cpu:
|
||||
unsigned at, v0, v1, a0, a1, a2, a3
|
||||
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
|
||||
unsigned gp, sp, fp, ra, hi, lo, k0, k1, pc
|
||||
Cpu cpu
|
||||
Thread *thread_prev, *thread_next
|
||||
Thread *schedule_prev, *schedule_next
|
||||
template <typename _T> struct Object : public Object_base:
|
||||
// Next and previous object of the same type in any page.
|
||||
_T *prev, *next
|
||||
void free (Memory *parent, _T *&first)
|
||||
|
||||
struct Free : public Object <Free>
|
||||
// This marker is ~0. No other kernel structure may allow this value
|
||||
// at this point. It is used to recognize free chunks.
|
||||
unsigned marker
|
||||
|
||||
bool Object_base::is_free ():
|
||||
return ((Free *)this)->marker == ~0
|
||||
|
||||
struct Page : public Object <Page>:
|
||||
void *physical
|
||||
|
||||
struct Thread : public Object <Thread>:
|
||||
Memory *address_space
|
||||
unsigned pc, sp
|
||||
Thread_arch arch
|
||||
Thread *schedule_prev, *schedule_next
|
||||
|
||||
struct Memory : public Object:
|
||||
Memory *memory_prev, *memory_next
|
||||
struct Memory : public Object <Memory>:
|
||||
Free *frees
|
||||
Page *pages
|
||||
Thread *threads
|
||||
Memory *memories
|
||||
unsigned limit, used
|
||||
struct Cpu:
|
||||
unsigned asid
|
||||
Page ***directory
|
||||
Cpu cpu
|
||||
Memory_arch arch
|
||||
|
||||
// Allocation of pages.
|
||||
void *palloc ()
|
||||
void *zalloc ()
|
||||
void pfree (void *page)
|
||||
void zfree (void *page)
|
||||
|
||||
// Allocation routines for kernel structures
|
||||
void *search_free (unsigned size, void *&first)
|
||||
Page *alloc_page ()
|
||||
Thread *alloc_thread ()
|
||||
Memory *alloc_memory ()
|
||||
|
||||
// Functions which can be called from assembly must not be mangled.
|
||||
extern "C":
|
||||
// Kernel entry points, called from entry.S.
|
||||
void init ()
|
||||
Thread *interrupt (Thread *current)
|
||||
Thread *cache_error (Thread *current)
|
||||
Thread *exception (Thread *current)
|
||||
|
||||
// tlb stuff. tlb_refill is also an entry point.
|
||||
void tlb_setup ()
|
||||
Thread *tlb_refill (Thread *current, unsigned EntryHi)
|
||||
|
||||
// Start running the idle task for the first time.
|
||||
void run_idle (Thread *self)
|
||||
|
||||
// Panic. n is sent over caps led. message is currently ignored.
|
||||
void panic (unsigned n, char const *message)
|
||||
// Debug: switch caps led
|
||||
void led (bool on, bool tick)
|
||||
|
||||
#ifndef EXTERN
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
struct FreePage:
|
||||
FreePage *next
|
||||
|
||||
@ -72,4 +81,13 @@ EXTERN Thread idle
|
||||
EXTERN Memory idle_memory
|
||||
EXTERN Page idle_page
|
||||
|
||||
template <typename _T> void Object <_T>::free (Memory *parent, _T *&first):
|
||||
if prev:
|
||||
prev->next = next
|
||||
else:
|
||||
first = next
|
||||
if next:
|
||||
next->prev = prev
|
||||
free_obj (parent)
|
||||
|
||||
#endif
|
||||
|
35
mips.hhp
Normal file
35
mips.hhp
Normal file
@ -0,0 +1,35 @@
|
||||
#pypp 0
|
||||
#ifndef _ARCH_HH
|
||||
#define _ARCH_HH
|
||||
|
||||
struct Thread_arch:
|
||||
unsigned at, v0, v1, a0, a1, a2, a3
|
||||
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
|
||||
unsigned gp, fp, ra, hi, lo, k0, k1
|
||||
|
||||
#define Thread_arch_init(thread) do { thread->at = 0; thread->v0 = 0; thread->v1 = 0; thread->a0 = 0; thread->a1 = 0; thread->a2 = 0; thread->a3 = 0; thread->t0 = 0; thread->t1 = 0; thread->t2 = 0; thread->t3 = 0; thread->t4 = 0; thread->t5 = 0; thread->t6 = 0; thread->t7 = 0; thread->t8 = 0; thread->t9 = 0; thread->gp = 0; thread->fp = 0; thread->ra = 0; thread->hi = 0; thread->lo = 0; thread->k0 = 0; thread->k1 = 0; } while (0)
|
||||
|
||||
struct Memory_arch:
|
||||
unsigned asid
|
||||
Page ***directory
|
||||
|
||||
EXTERN unsigned g_asid
|
||||
|
||||
#define Memory_arch_init(mem) do { mem->asid = g_asid++; g_asid &= 0x3f; mem->directory = NULL; } while (0)
|
||||
|
||||
// Functions which can be called from assembly must not be mangled.
|
||||
extern "C":
|
||||
// Kernel entry points, called from entry.S.
|
||||
Thread *interrupt (Thread *current)
|
||||
Thread *cache_error (Thread *current)
|
||||
Thread *exception (Thread *current)
|
||||
Thread *tlb_refill (Thread *current, unsigned EntryHi)
|
||||
|
||||
#ifdef INIT
|
||||
// Initialize most things (the rest is done in boot.S)
|
||||
void init ()
|
||||
// Start running the idle task for the first time.
|
||||
void run_idle (Thread *self)
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user