1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-07-02 22:53:52 +03:00
iris/init.ccp

203 lines
6.9 KiB
Plaintext
Raw Normal View History

2009-05-14 21:31:47 +03:00
#pypp 0
2009-05-18 10:30:27 +03:00
// Also declare things which only work during kernel init.
#define INIT
2009-05-22 23:48:49 +03:00
#define ARCH
2009-05-14 21:31:47 +03:00
#include "kernel.hh"
2009-05-22 23:48:49 +03:00
#include "elf.h"
2009-05-18 10:30:27 +03:00
2009-05-14 21:31:47 +03:00
static void init_idle ():
// initialize idle task as if it is currently running.
2009-05-19 00:18:23 +03:00
idle.prev_obj = NULL
idle.next_obj = NULL
2009-05-14 21:31:47 +03:00
idle.prev = NULL
idle.next = NULL
idle.schedule_prev = NULL
idle.schedule_next = NULL
idle.address_space = &idle_memory
// initialize idle_memory.
2009-05-19 00:18:23 +03:00
idle_memory.prev_obj = NULL
idle_memory.next_obj = NULL
2009-05-14 21:31:47 +03:00
idle_memory.prev = NULL
idle_memory.next = NULL
idle_memory.pages = &idle_page
idle_memory.threads = &idle
idle_memory.memories = NULL
idle_memory.limit = 0
idle_memory.used = 0
2009-05-20 23:07:56 +03:00
idle_memory.arch.directory = (unsigned **)0x80000000
2009-05-19 00:18:23 +03:00
idle_memory.arch.asid = 0
2009-05-14 21:31:47 +03:00
// initialize idle_page
2009-05-19 00:18:23 +03:00
idle_page.prev_obj = NULL
idle_page.next_obj = NULL
2009-05-14 21:31:47 +03:00
idle_page.prev = NULL
idle_page.next = NULL
2009-05-23 21:55:31 +03:00
idle_page.physical = 0x80000000
current = &idle
2009-05-14 21:31:47 +03:00
static void init_cp0 ():
2009-05-18 10:30:27 +03:00
// Set timer to a defined value
2009-05-19 00:18:23 +03:00
cp0_set (CP0_COMPARE, 1000000)
2009-05-18 10:30:27 +03:00
// Reset timer
2009-05-19 00:18:23 +03:00
cp0_set0 (CP0_COUNT)
2009-05-18 10:30:27 +03:00
// Use the interrupt vector for interrupts
2009-05-19 00:18:23 +03:00
cp0_set (CP0_CAUSE, 1 << 23)
2009-05-14 21:31:47 +03:00
// clear the tlb, hardwire page 0 to 0xffffffff
// and soft-wire it to (0x294 << 20) + (0x290 << 10)
// (for the idle task).
2009-05-19 00:18:23 +03:00
cp0_set (CP0_WIRED, 1)
cp0_set0 (CP0_PAGE_MASK)
cp0_set0 (CP0_ENTRY_LO0)
cp0_set0 (CP0_ENTRY_LO1)
2009-05-14 21:31:47 +03:00
// Get number of tlb entries (is 31).
2009-05-22 23:48:49 +03:00
unsigned num
cp0_get (CP0_CONFIG1, num)
2009-05-14 21:31:47 +03:00
num >>= 25
num &= 0x3f
// Clear the tlb.
2009-05-22 23:48:49 +03:00
for unsigned i = 1; i <= num; ++i:
// with asid 0, no page faults will be triggered, so it's safe to map memory anywhere.
cp0_set (CP0_ENTRY_HI, 0x2000 * i)
2009-05-19 00:18:23 +03:00
cp0_set (CP0_INDEX, i)
2009-05-14 21:31:47 +03:00
// write the data.
__asm__ volatile ("tlbwi")
// Fill the upper page in kseg3.
2009-05-22 23:48:49 +03:00
cp0_set (CP0_ENTRY_HI, 0xffffe000)
2009-05-19 00:18:23 +03:00
cp0_set (CP0_ENTRY_LO0, 0x1d)
cp0_set (CP0_ENTRY_LO1, 0x1f)
cp0_set0 (CP0_INDEX)
2009-05-14 21:31:47 +03:00
__asm__ volatile ("tlbwi")
// Fill the idle task's page in useg. Set it to non-cachable.
2009-05-19 00:18:23 +03:00
cp0_set (CP0_ENTRY_HI, 0x284a0000)
cp0_set (CP0_ENTRY_LO0, 0x16)
cp0_set (CP0_ENTRY_LO1, 0x14)
2009-05-14 21:31:47 +03:00
__asm__ volatile ("tlbwr")
// Allow eret to be used to jump to the idle task.
2009-05-19 00:18:23 +03:00
cp0_set (CP0_EPC, 0x284a0288)
2009-05-23 21:55:31 +03:00
// Wait with initializing the status register until the last moment, so that
// exceptions in the bootup code will fill EPC and friends.
2009-05-18 10:30:27 +03:00
static void init_threads ():
2009-05-23 21:55:31 +03:00
Thread *previous = NULL
first_scheduled = NULL
2009-05-18 10:30:27 +03:00
for unsigned i = 0; i < NUM_THREADS; ++i:
Memory *mem = top_memory.alloc_memory ()
Thread *thread = mem->alloc_thread ()
2009-05-23 21:55:31 +03:00
Page **pages = (Page **)mem->zalloc ()
2009-05-22 23:48:49 +03:00
Elf32_Ehdr *header = (Elf32_Ehdr *)thread_start[i]
for unsigned j = 0; j < SELFMAG; ++j:
if header->e_ident[j] != ELFMAG[j]:
panic (i * 0x1000 + j, "invalid ELF magic")
if header->e_ident[EI_CLASS] != ELFCLASS32:
panic (i * 0x1000 + EI_CLASS, "invalid ELF class")
if header->e_ident[EI_DATA] != ELFDATA2LSB:
panic (i * 0x1000 + EI_DATA, "invalid ELF data")
if header->e_ident[EI_VERSION] != EV_CURRENT:
panic (i * 0x1000 + EI_VERSION, "invalid ELF version")
if header->e_type != ET_EXEC:
panic (i * 0x1000 + 0x10, "invalid ELF type")
2009-05-23 21:55:31 +03:00
if header->e_machine != EM_MIPS_RS3_LE && header->e_machine != EM_MIPS:
panic (i * 0x1000 + 0x12, "invalid ELF machine")
2009-05-22 23:48:49 +03:00
thread->pc = header->e_entry
thread->sp = 0x80000000
for unsigned section = 0; section < header->e_shnum; ++section:
Elf32_Shdr *shdr = (Elf32_Shdr *)(thread_start[i] + header->e_shoff + section * header->e_shentsize)
if !(shdr->sh_flags & SHF_ALLOC):
continue
bool writable = shdr->sh_flags & SHF_WRITE
//bool executable = shdr->sh_flags & SHF_EXEC_INSTR
if shdr->sh_type != SHT_NOBITS:
for unsigned p = (shdr->sh_addr & PAGE_MASK); p <= ((shdr->sh_addr + shdr->sh_size - 1) & PAGE_MASK); p += PAGE_SIZE:
unsigned idx = (p - (shdr->sh_addr & PAGE_MASK)) >> PAGE_BITS
if !pages[idx]:
pages[idx] = mem->alloc_page ()
pages[idx]->physical = thread_start[i] + (idx << PAGE_BITS)
++top_memory.limit
if !mem->map (pages[idx], p, writable):
panic (0x22446688, "unable to map initial page")
else:
for unsigned p = (shdr->sh_addr & PAGE_MASK); p <= ((shdr->sh_addr + shdr->sh_size - 1) & PAGE_MASK); p += PAGE_SIZE:
Page *page = mem->get_mapping (p)
if !page:
page = mem->alloc_page ()
if !page:
panic (0x00220022, "out of memory")
page->physical = mem->zalloc ()
if !page->physical || !mem->map (page, p, true):
panic (0x33557799, "unable to map initial bss page")
else:
for unsigned a = p; a < p + PAGE_SIZE; a += 4:
if a >= shdr->sh_addr + shdr->sh_size:
break
if a < shdr->sh_addr:
continue
2009-05-23 21:55:31 +03:00
((unsigned *)page->physical)[(a & ~PAGE_MASK) >> 2] = 0
2009-05-22 23:48:49 +03:00
for unsigned p = 0; p <= ((thread_start[i + 1] - thread_start[i] - 1) >> PAGE_BITS); ++p:
2009-05-23 21:55:31 +03:00
// TODO: this also skips pages where new space is allocated.
2009-05-22 23:48:49 +03:00
if pages[p]:
continue
++top_memory.limit
top_memory.zfree (thread_start[i] + (p << PAGE_BITS))
Page *stackpage = mem->alloc_page ()
stackpage->physical = mem->zalloc ()
if !stackpage || !mem->map (stackpage, 0x7ffff000, true):
panic (0x13151719, "unable to map initial stack page")
thread->arch.a0 = (unsigned)mem->alloc_receiver ()
thread->arch.a1 = (unsigned)&top_memory
thread->arch.a2 = (unsigned)mem
Capability *admin = mem->alloc_capability ((Receiver *)(CAPTYPE_ADMIN | ~PAGE_MASK), &mem->capabilities, ~0)
thread->arch.a3 = (unsigned)admin
mem->pfree ((unsigned)pages)
2009-05-23 21:55:31 +03:00
thread->schedule_next = NULL
thread->schedule_prev = previous
if previous:
previous->schedule_next = thread
else:
first_scheduled = thread
previous = thread
2009-05-14 21:31:47 +03:00
2009-05-22 23:48:49 +03:00
// Initialize the kernel, finish by falling into the idle task.
2009-05-14 21:31:47 +03:00
extern unsigned _end
void init ():
2009-05-23 21:55:31 +03:00
// Disable interrupts and set interrupt vectors to normal.
cp0_set0 (CP0_STATUS)
2009-05-14 21:31:47 +03:00
// Initialize kernel variables to empty.
sleepers = NULL
runners = NULL
zero_pages = NULL
// Fill junk pages with all memory not currently used.
junk_pages = (FreePage *)(((unsigned)&_end + (1 << 12) - 1) & ~((1 << 12) - 1))
FreePage *p, *next
unsigned count = 1
for p = junk_pages, next = p; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + (1 << 12)):
p->next = next
++count
p->next = NULL
// initialize system control coprocessor.
init_cp0 ()
// initialize everything about the idle task.
init_idle ()
// initialize top_memory.
2009-05-19 00:18:23 +03:00
top_memory.prev_obj = NULL
top_memory.next_obj = NULL
2009-05-14 21:31:47 +03:00
top_memory.prev = NULL
top_memory.next = NULL
2009-05-22 23:48:49 +03:00
top_memory.parent = NULL
2009-05-14 21:31:47 +03:00
top_memory.pages = NULL
top_memory.threads = NULL
top_memory.memories = NULL
top_memory.limit = count
top_memory.used = 0
2009-05-19 00:18:23 +03:00
top_memory.arch.directory = NULL
top_memory.arch.asid = 0
2009-05-18 10:30:27 +03:00
init_threads ()
2009-05-14 21:31:47 +03:00
2009-05-23 21:55:31 +03:00
// Enable all interrupts and say we're handling an exception.
// Since we're going to enter the idle task, allow access to cp0.
cp0_set (CP0_STATUS, 0x1000ff13)
2009-05-14 21:31:47 +03:00
// Done; return to user space (the idle task).
__asm__ volatile ("eret")