#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) idle.prev = NULL idle.next = NULL idle.thread_prev = NULL idle.thread_next = NULL idle.schedule_prev = NULL idle.schedule_next = NULL idle.address_space = &idle_memory // initialize idle_memory. idle_memory.size = sizeof (Memory) idle_memory.prev = NULL idle_memory.next = NULL idle_memory.memory_prev = NULL idle_memory.memory_next = NULL idle_memory.pages = &idle_page idle_memory.threads = &idle idle_memory.memories = NULL idle_memory.limit = 0 idle_memory.used = 0 idle_memory.cpu.directory = (Page ***)0x80000000 idle_memory.cpu.asid = 0 // initialize idle_page idle_page.size = sizeof (Page) idle_page.prev = NULL idle_page.next = NULL idle_page.page_prev = NULL idle_page.page_next = NULL // Not an error, this is really physical page 0. idle_page.physical = 0 static void init_cp0 (): // 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). 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; 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. cp0_set (ENTRY_HI, 0x70000000 + 0x1000 * i) cp0_set (INDEX, i) // write the data. __asm__ volatile ("tlbwi") #endif // Fill the upper page in kseg3. 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. 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. cp0_set (EPC, 0x284a0288) // 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 (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 void init (): // 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. top_memory.size = sizeof (Memory) top_memory.prev = NULL top_memory.next = NULL top_memory.memory_prev = NULL top_memory.memory_next = NULL top_memory.pages = NULL top_memory.threads = NULL top_memory.memories = NULL top_memory.limit = count top_memory.used = 0 top_memory.cpu.directory = NULL top_memory.cpu.asid = 0 init_threads () // Done; return to user space (the idle task). __asm__ volatile ("eret")