2009-05-20 23:07:56 +03:00
|
|
|
#pypp 0
|
2009-05-22 23:48:49 +03:00
|
|
|
#define ARCH
|
2009-05-20 23:07:56 +03:00
|
|
|
#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
|
|
|
|
|
2009-05-25 01:31:35 +03:00
|
|
|
void Thread_arch_receive (Thread *thread, unsigned d[4], Capability *c[4]):
|
|
|
|
thread->arch.a0 = (unsigned)c[0]
|
|
|
|
thread->arch.a1 = (unsigned)c[1]
|
|
|
|
thread->arch.a2 = (unsigned)c[2]
|
|
|
|
thread->arch.a3 = (unsigned)c[3]
|
|
|
|
thread->arch.t0 = d[0]
|
|
|
|
thread->arch.t1 = d[1]
|
|
|
|
thread->arch.t2 = d[2]
|
|
|
|
thread->arch.t3 = d[3]
|
|
|
|
thread->arch.v0 = 1
|
|
|
|
|
|
|
|
void Thread_arch_receive_fail (Thread *thread):
|
|
|
|
thread->arch.v0 = 0
|
|
|
|
|
2009-05-20 23:07:56 +03:00
|
|
|
void Memory_arch_init (Memory *mem):
|
2009-05-24 13:22:22 +03:00
|
|
|
mem->arch.asid = 1
|
2009-05-20 23:07:56 +03:00
|
|
|
mem->arch.directory = NULL
|
2009-05-26 01:42:47 +03:00
|
|
|
mem->arch.shadow = NULL
|
2009-05-20 23:07:56 +03:00
|
|
|
|
2009-05-24 13:22:22 +03:00
|
|
|
static void flush_tlb (unsigned asid):
|
|
|
|
for unsigned tlb = 1; tlb < 32; ++tlb:
|
|
|
|
cp0_set (CP0_INDEX, tlb)
|
|
|
|
__asm__ volatile ("tlbr")
|
|
|
|
unsigned hi
|
|
|
|
cp0_get (CP0_ENTRY_HI, hi)
|
|
|
|
if (hi & 0x1f) == asid:
|
|
|
|
// Set asid to 0, which is only used by the idle task.
|
|
|
|
cp0_set (CP0_ENTRY_HI, 0x2000 * tlb)
|
|
|
|
__asm__ volatile ("tlbwi")
|
|
|
|
|
2009-05-20 23:07:56 +03:00
|
|
|
void Memory_arch_free (Memory *mem):
|
2009-05-26 01:42:47 +03:00
|
|
|
while mem->arch.first_page_table:
|
|
|
|
mem->unmap (mem->arch.first_page_table->first_page->page, mem->arch.first_page_table->first_page->mapping)
|
2009-05-24 13:22:22 +03:00
|
|
|
if (Memory *)asids[mem->arch.asid] == mem:
|
|
|
|
flush_tlb (mem->arch.asid)
|
|
|
|
asids[mem->arch.asid] = asids[0]
|
|
|
|
asids[0] = mem->arch.asid
|
2009-05-20 23:07:56 +03:00
|
|
|
mem->unuse ()
|
2009-05-22 23:48:49 +03:00
|
|
|
mem->zfree ((unsigned)mem->arch.directory)
|
2009-05-20 23:07:56 +03:00
|
|
|
|
2009-05-26 01:42:47 +03:00
|
|
|
static arch_page_table *alloc_page_table (Memory *mem):
|
|
|
|
arch_page_table *ret = (arch_page_table *)mem->search_free (sizeof (arch_page_table), (void **)&mem->arch.first_page_table)
|
|
|
|
if !ret:
|
|
|
|
return NULL
|
|
|
|
ret->first_page = NULL
|
|
|
|
return ret
|
|
|
|
|
|
|
|
static arch_page *alloc_page (Memory *mem, arch_page_table *t):
|
|
|
|
arch_page *ret = (arch_page *)mem->search_free (sizeof (arch_page), (void **)&t->first_page)
|
|
|
|
if !ret:
|
|
|
|
return NULL
|
|
|
|
ret->page = NULL
|
|
|
|
ret->mapping = ~0
|
|
|
|
ret->prev_mapped = NULL
|
|
|
|
ret->next_mapped = NULL
|
|
|
|
return ret
|
|
|
|
|
|
|
|
static void free_page_table (arch_page_table *t, unsigned idx):
|
|
|
|
Memory *mem = t->address_space
|
|
|
|
if t->next:
|
|
|
|
t->next->prev = t->prev
|
|
|
|
if t->prev:
|
|
|
|
t->prev->next = t->next
|
|
|
|
else:
|
|
|
|
mem->arch.first_page_table = t->next
|
|
|
|
mem->zfree ((unsigned)mem->arch.directory[idx])
|
|
|
|
mem->arch.directory[idx] = NULL
|
|
|
|
mem->arch.shadow[idx] = NULL
|
|
|
|
mem->free_obj (t)
|
|
|
|
if !mem->arch.first_page_table:
|
|
|
|
mem->zfree ((unsigned)mem->arch.directory)
|
|
|
|
mem->zfree ((unsigned)mem->arch.shadow)
|
|
|
|
mem->arch.directory = NULL
|
|
|
|
mem->arch.shadow = NULL
|
|
|
|
|
|
|
|
static void free_page (arch_page_table *t, arch_page *p):
|
|
|
|
if p->next:
|
|
|
|
p->next->prev = p->prev
|
|
|
|
if p->prev:
|
|
|
|
p->prev->next = p->next
|
|
|
|
else:
|
|
|
|
t->first_page = p->next
|
|
|
|
if p->prev_mapped:
|
|
|
|
p->prev_mapped->next_mapped = p->next_mapped
|
|
|
|
else:
|
|
|
|
p->page->arch.first_mapped = p->next_mapped
|
|
|
|
if p->next_mapped:
|
|
|
|
p->next_mapped->prev_mapped = p->prev_mapped
|
|
|
|
unsigned idx = p->mapping >> 21
|
|
|
|
p->address_space->free_obj (p)
|
|
|
|
if !t->first_page:
|
|
|
|
free_page_table (t, idx)
|
|
|
|
|
2009-05-20 23:07:56 +03:00
|
|
|
bool Memory_arch_map (Memory *mem, Page *page, unsigned address, bool write):
|
2009-05-23 21:55:31 +03:00
|
|
|
if !mem->arch.directory:
|
|
|
|
mem->arch.directory = (unsigned **)mem->zalloc ()
|
|
|
|
if !mem->arch.directory:
|
|
|
|
return false
|
2009-05-26 01:42:47 +03:00
|
|
|
mem->arch.shadow = (arch_page_table **)mem->zalloc ()
|
|
|
|
if !mem->arch.shadow:
|
|
|
|
mem->zfree ((unsigned)mem->arch.directory)
|
|
|
|
mem->arch.directory = NULL
|
|
|
|
return false
|
|
|
|
unsigned *table = mem->arch.directory[address >> 21]
|
|
|
|
arch_page_table *t = mem->arch.shadow[address >> 21]
|
2009-05-20 23:07:56 +03:00
|
|
|
if !table:
|
|
|
|
table = (unsigned *)mem->zalloc ()
|
|
|
|
if !table:
|
2009-05-26 01:42:47 +03:00
|
|
|
if !mem->arch.first_page_table:
|
|
|
|
mem->zfree ((unsigned)mem->arch.directory)
|
|
|
|
mem->zfree ((unsigned)mem->arch.shadow)
|
2009-05-27 15:38:52 +03:00
|
|
|
mem->arch.directory = NULL
|
|
|
|
mem->arch.shadow = NULL
|
2009-05-26 01:42:47 +03:00
|
|
|
return false
|
|
|
|
t = alloc_page_table (mem)
|
|
|
|
if !t:
|
|
|
|
mem->zfree ((unsigned)table)
|
|
|
|
if !mem->arch.first_page_table:
|
|
|
|
mem->zfree ((unsigned)mem->arch.directory)
|
|
|
|
mem->zfree ((unsigned)mem->arch.shadow)
|
2009-05-27 15:38:52 +03:00
|
|
|
mem->arch.directory = NULL
|
|
|
|
mem->arch.shadow = NULL
|
2009-05-20 23:07:56 +03:00
|
|
|
return false
|
2009-05-26 01:42:47 +03:00
|
|
|
mem->arch.directory[address >> 21] = table
|
2009-05-27 15:38:52 +03:00
|
|
|
mem->arch.shadow[address >> 21] = t
|
2009-05-26 01:42:47 +03:00
|
|
|
arch_page *p = alloc_page (mem, t)
|
|
|
|
if !p:
|
|
|
|
if !t->first_page:
|
|
|
|
// This automatically cleans up the rest.
|
|
|
|
free_page_table (t, address >> 21)
|
|
|
|
return false
|
|
|
|
unsigned idx = (address >> 12) & ((1 << 9) - 1)
|
2009-05-20 23:07:56 +03:00
|
|
|
if table[idx]:
|
2009-05-26 01:42:47 +03:00
|
|
|
mem->unmap ((Page *)table[idx + 0x200], address)
|
2009-05-27 15:38:52 +03:00
|
|
|
table[idx] = page->physical ? ((page->physical & ~0x80000000) >> 6) | 0x18 | (write ? 0x4 : 0) | 0x2 : 0
|
2009-05-26 01:42:47 +03:00
|
|
|
table[idx + 0x200] = (unsigned)p
|
|
|
|
p->mapping = address
|
|
|
|
p->page = page
|
|
|
|
p->next_mapped = page->arch.first_mapped
|
|
|
|
if p->next_mapped:
|
|
|
|
p->next_mapped->prev_mapped = p
|
|
|
|
page->arch.first_mapped = p
|
2009-05-23 21:55:31 +03:00
|
|
|
return true
|
2009-05-20 23:07:56 +03:00
|
|
|
|
|
|
|
void Memory_arch_unmap (Memory *mem, Page *page, unsigned address):
|
2009-05-26 01:42:47 +03:00
|
|
|
unsigned didx = address >> 21
|
|
|
|
unsigned tidx = (address >> 12) & ((1 << 9) - 1)
|
|
|
|
unsigned *table = mem->arch.directory[didx]
|
|
|
|
arch_page_table *t = mem->arch.shadow[didx]
|
|
|
|
table[tidx] = 0
|
|
|
|
arch_page *p = (arch_page *)table[tidx + 0x200]
|
|
|
|
table[tidx + 0x200] = 0
|
|
|
|
free_page (t, p)
|
2009-05-20 23:07:56 +03:00
|
|
|
|
2009-05-24 13:22:22 +03:00
|
|
|
Page *Memory_arch_get_mapping (Memory *mem, unsigned address, bool *writable):
|
2009-05-26 01:42:47 +03:00
|
|
|
unsigned *table = mem->arch.directory[address >> 21]
|
|
|
|
unsigned idx = (address >> 12) & ((1 << 9) - 1)
|
|
|
|
arch_page *page = (arch_page *)table[idx + 0x200]
|
2009-05-24 13:22:22 +03:00
|
|
|
if writable:
|
2009-05-26 01:42:47 +03:00
|
|
|
*writable = (table[idx] & 4 ? 1 : 0)
|
|
|
|
return page->page
|
2009-05-20 23:07:56 +03:00
|
|
|
|
2009-05-23 21:55:31 +03:00
|
|
|
void arch_invoke ():
|
2009-05-25 01:31:35 +03:00
|
|
|
Capability *target, *c[4]
|
|
|
|
bool wait, copy[4]
|
|
|
|
Thread *caller = current
|
|
|
|
target = caller->address_space->find_capability (current->arch.v0, &wait)
|
|
|
|
if wait:
|
|
|
|
caller->wait ()
|
2009-05-20 23:07:56 +03:00
|
|
|
if !target:
|
|
|
|
// TODO: there must be no action here. This is just because the rest doesn't work yet.
|
2009-05-25 01:31:35 +03:00
|
|
|
dbg_led (caller->arch.a0, caller->arch.a1, caller->arch.a2)
|
2009-05-23 21:55:31 +03:00
|
|
|
dbg_sleep (1000)
|
2009-05-20 23:07:56 +03:00
|
|
|
schedule ()
|
2009-05-25 01:31:35 +03:00
|
|
|
// Calling an invalid capability always fails.
|
|
|
|
caller->arch.v0 = 0
|
2009-05-27 15:38:52 +03:00
|
|
|
else:
|
|
|
|
c[0] = caller->address_space->find_capability (caller->arch.a0, ©[0])
|
|
|
|
c[1] = caller->address_space->find_capability (caller->arch.a1, ©[1])
|
|
|
|
c[2] = caller->address_space->find_capability (caller->arch.a2, ©[2])
|
|
|
|
c[3] = caller->address_space->find_capability (caller->arch.a3, ©[3])
|
|
|
|
unsigned d[4]
|
|
|
|
d[0] = caller->arch.t0
|
|
|
|
d[1] = caller->arch.t1
|
|
|
|
d[2] = caller->arch.t2
|
|
|
|
d[3] = caller->arch.t3
|
|
|
|
caller->arch.v0 = target->invoke (d, c, copy) ? 1 : 0
|
2009-05-25 01:31:35 +03:00
|
|
|
if caller != current:
|
|
|
|
if (Memory *)asids[current->address_space->arch.asid] != current->address_space:
|
|
|
|
if asids[0]:
|
|
|
|
current->address_space->arch.asid = asids[0]
|
|
|
|
asids[0] = asids[asids[0]]
|
|
|
|
else:
|
|
|
|
static unsigned random = 1
|
|
|
|
current->address_space->arch.asid = random
|
|
|
|
// Overwrite used asid, so flush those values from tlb.
|
|
|
|
flush_tlb (random)
|
|
|
|
++random
|
|
|
|
if random >= 64:
|
|
|
|
random = 1
|
2009-05-27 15:38:52 +03:00
|
|
|
asids[current->address_space->arch.asid] = (unsigned)current->address_space
|
2009-05-25 01:31:35 +03:00
|
|
|
cp0_set (CP0_ENTRY_HI, current->address_space->arch.asid)
|
2009-05-26 01:42:47 +03:00
|
|
|
directory = current->address_space->arch.directory
|
2009-05-27 15:38:52 +03:00
|
|
|
unsigned status
|
|
|
|
cp0_get (CP0_STATUS, status)
|
|
|
|
status &= 0x0fffffff
|
|
|
|
if current->flags & THREAD_FLAG_PRIV:
|
|
|
|
status |= 0x10000000
|
|
|
|
cp0_set (CP0_STATUS, status | 0x13)
|