From 5d9d12b860e12aec9d5723ad9aa4f0d6f33c9f25 Mon Sep 17 00:00:00 2001 From: Bas Wijnen Date: Thu, 14 May 2009 20:31:47 +0200 Subject: [PATCH] idle --- .gitignore | 1 + Makefile | 14 +-- boot.S | 45 ++++++++++ entry.S | 234 ++++++++++++++++++------------------------------- init.ccp | 125 ++++++++++++++++++++++++++ interrupts.ccp | 68 +------------- panic.ccp | 6 +- start.S | 24 ----- 8 files changed, 269 insertions(+), 248 deletions(-) create mode 100644 boot.S create mode 100644 init.ccp delete mode 100644 start.S diff --git a/.gitignore b/.gitignore index 1375e3e..620b67c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ all +all.raw all.raw.gz report uimage diff --git a/Makefile b/Makefile index 531d713..55d7a71 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -load = 0xa0000000 +load = 0x80000000 CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc CPPFLAGS = -O5 -Wa,-mips32 @@ -8,7 +8,9 @@ LD = $(CROSS)ld OBJCOPY = $(CROSS)objcopy OBJDUMP = $(CROSS)objdump -BUILT_SOURCES = interrupts.cc panic.cc data.cc test.cc +kernel_sources = interrupts.cc panic.cc data.cc test.cc +boot_sources = init.cc +BUILT_SOURCES = $(kernel_sources) $(boot_sources) PYPP = /usr/bin/pypp %.cc: %.ccp kernel.hh @@ -17,8 +19,8 @@ PYPP = /usr/bin/pypp $(PYPP) --name $< < $< > $@ # Transform ':' into ';' so vim doesn't think there are errors. -uimage: all.raw.gz Makefile - mkimage -A MIPS -O Linux -C gzip -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' +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 $(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@ @@ -26,8 +28,8 @@ uimage: all.raw.gz Makefile %.o:%.S Makefile $(CC) $(CPPFLAGS) -DKERNEL_STACK_SIZE=0x2000 -c $< -o $@ -# entry.o must be the first file. For the rest, the order doesn't matter. -all: entry.o $(subst .cc,.o,$(BUILT_SOURCES)) +# entry.o must be the first file. boot.o must be the first of the init objects (which can be dumped after loading). +all: entry.o $(subst .cc,.o,$(kernel_sources)) boot.o $(subst .cc,.o,$(boot_sources)) $(LD) --omagic -Ttext $(load) $^ -o $@ junk = mdebug.abi32 reginfo comment pdr diff --git a/boot.S b/boot.S new file mode 100644 index 0000000..ff30261 --- /dev/null +++ b/boot.S @@ -0,0 +1,45 @@ + // The kernel stack. + .lcomm kernel_stack, KERNEL_STACK_SIZE + + .globl __start + .set noreorder + +#define Status 12 +#define Config 16 + +__start: + bal 1f + nop + .word _gp +// For some reason the disassembler considers everything +// after __start non-code until the next label. So I add a label. +start_hack_for_disassembler: +1: lw $gp, 0($ra) + + la $sp, kernel_stack + KERNEL_STACK_SIZE + + // Disable interrupts during bootstrap. + mtc0 $zero, $Status + + // TODO: flush cache and optionally refill it. + + // Set kseg0 cachable. + li $k0, 0x3 + mtc0 $k0, $Config, 0 + + // Jump into cached code. + la $t9, 1f + jr $t9 + nop +1: + + // Clear .bss + la $a0, _edata + la $a1, _end +1: sw $zero, 0($a0) + bne $a1, $a0, 1b + addu $a0, 4 + + la $t9, init + jr $t9 + nop diff --git a/entry.S b/entry.S index 2ab3ca5..8c8b3da 100644 --- a/entry.S +++ b/entry.S @@ -1,73 +1,15 @@ // The kernel stack. .lcomm kernel_stack, KERNEL_STACK_SIZE - .globl __start .globl run_idle .set noat - .set noreorder #define EntryLo0 2 #define EntryLo1 3 #define EntryHi 10 #define Random 1 #define Index 0 -#define PageMask 5 -#define Wired 6 -#define Config 16 #define Status 12 -#define Cause 13 -#define Compare 11 - -#define save_regs \ - sw $k0, -0x180($zero) ;\ - lw $k0, -0x184($zero) ;\ - sw $at, 12($k0) ;\ - sw $k1, 108($k0) ;\ - lw $k1, -0x180($zero) ;\ - sw $k1, 104($k0) ;\ - sw $v0, 16($k0) ;\ - sw $v1, 20($k0) ;\ - sw $t0, 40($k0) ;\ - sw $sp, 84($k0) ;\ - sw $fp, 88($k0) ;\ - sw $ra, 92($k0) ;\ - lw $gp, -12($zero) ;\ - la $sp, kernel_stack + KERNEL_STACK_SIZE ;\ - move $a0, $k0 ;\ - la $ra, kernel_exit ;\ - bal save_args - -#define restore_regs \ - lw $v0, 96($k0) ;\ - lw $v1, 100($k0) ;\ - mthi $v0 ;\ - mtlo $v1 ;\ - lw $v0, 16($k0) ;\ - lw $v1, 20($k0) ;\ - lw $a0, 24($k0) ;\ - lw $a1, 28($k0) ;\ - lw $a2, 32($k0) ;\ - lw $a3, 36($k0) ;\ - lw $t0, 40($k0) ;\ - lw $t1, 44($k0) ;\ - lw $t2, 48($k0) ;\ - lw $t3, 52($k0) ;\ - lw $t4, 56($k0) ;\ - lw $t5, 60($k0) ;\ - lw $t6, 64($k0) ;\ - lw $t7, 68($k0) ;\ - lw $t8, 72($k0) ;\ - lw $t9, 76($k0) ;\ - lw $gp, 80($k0) ;\ - lw $sp, 84($k0) ;\ - lw $fp, 88($k0) ;\ - lw $ra, 92($k0) ;\ - lw $at, 12($k0) ;\ - lw $k1, 104($k0) ;\ - sw $k1, -0x180($zero) ;\ - lw $k1, 108($k0) ;\ - sw $k0, -0x184($zero) ;\ - lw $k0, -0x180($zero) addr_000: // TLB refill @@ -76,9 +18,10 @@ addr_000: li $a0, 0xffff0000 la $t9, panic jr $t9 + nop - save_regs - mfc0 $a1, $EntryHi + sw $ra, -0x188($zero) + bal save_regs la $t9, tlb_refill jr $t9 nop @@ -90,8 +33,10 @@ addr_100: li $a0, 0xaaaa0000 la $t9, panic jr $t9 + nop - save_regs + sw $ra, -0x188($zero) + bal save_regs la $t9, cache_error jr $t9 nop @@ -100,11 +45,13 @@ addr_180: // General exception // TODO - li $a0, 0xaaff0000 + //li $a0, 0xaaff0000 la $t9, panic jr $t9 + nop - save_regs + sw $ra, -0x188($zero) + bal save_regs la $t9, exception jr $t9 nop @@ -116,85 +63,83 @@ addr_200: li $a0, 0x0a0f0000 la $t9, panic jr $t9 + nop - save_regs + sw $ra, -0x188($zero) + bal save_regs la $t9, interrupt jr $t9 nop - .fill 0x280 - (. - addr_000) + .fill 0x280 - (. - addr_000) - 16 - // space for save_regs. + // space for save_regs: k0; current Thread; ra; gp + .word 0 .word 0 .word 0 - -start_idle: - b . - nop - .word idle_page - .word 0x80000000 // A pointer to the current page. - -__start: - bal 1f - nop .word _gp -// For some reason the disassembler considers everything -// after __start non-code until the next label. So I add a label. -start_hack: -1: lw $gp, 0($ra) - la $sp, kernel_stack + KERNEL_STACK_SIZE - - // Disable interrupts during bootstrap. - mtc0 $zero, $Status - - // TODO: flush cache - - // Set kseg0 cachable. - li $k0, 0x3 - mtc0 $k0, $Config, 0 - - // Clear .bss - la $a0, _edata - la $a1, _end -1: sw $zero, 0($a0) - bne $a1, $a0, 1b - addu $a0, 4 - - // Set timer to a defined value - mtc0 $zero, $Compare, 0 - - // Use the interrupt vector for interrupts - li $k0, 1 << 23 - mtc0 $k0, $Cause - - li $a0, 0xff0a0000 - la $t9, panic - jr $t9 - - // clear the tlb, hardwire page 0 to 0xffffffff - // and soft-wire it to (0x294 << 20) + (0x290 << 10) - // (for the idle task). - - // this address doesn't reach the tlb, so it can't trigger exceptions. - mtc0 $zero, $PageMask - mtc0 $zero, $EntryLo0 - mtc0 $zero, $EntryLo1 - li $t0, 0x80000000 - // There are 32 tlb entries. - addi $a0, $zero, 31 -1: mtc0 $t0, $EntryHi - mtc0 $a0, $Index - tlbwi - addiu $t0, $t0, 1 << 13 - bgtz $a0, 1b - addiu $a0, $a0, -1 - - la $t9, init - jalr $t9 + .word idle_page // 280 + .word 0x80000000 // 284 A pointer to the current page. +start_idle: // 288 + // Wait for the next interrupt, then the first thread will be scheduled. + // It is impractical to try to call schedule, because for that the + // idle task would need to own capabilities. + mfc0 $a0, $9 + syscall +1: wait + b 1b nop - sw $gp, -12($zero) -save_args: +kernel_exit: + move $k0, $v0 + lw $v0, 96($k0) + lw $v1, 100($k0) + mthi $v0 + mtlo $v1 + lw $v0, 16($k0) + lw $v1, 20($k0) + lw $a0, 24($k0) + lw $a1, 28($k0) + lw $a2, 32($k0) + lw $a3, 36($k0) + lw $t0, 40($k0) + lw $t1, 44($k0) + lw $t2, 48($k0) + lw $t3, 52($k0) + lw $t4, 56($k0) + lw $t5, 60($k0) + lw $t6, 64($k0) + lw $t7, 68($k0) + lw $t8, 72($k0) + lw $t9, 76($k0) + lw $gp, 80($k0) + lw $sp, 84($k0) + lw $fp, 88($k0) + lw $ra, 92($k0) + lw $at, 12($k0) + lw $k1, 104($k0) // Real $k0 + sw $k1, -0x190($zero) + lw $k1, 108($k0) + sw $k0, -0x18c($zero) + lw $k0, -0x190($zero) + eret + +save_regs: + sw $k0, -0x190($zero) + lw $k0, -0x18c($zero) + sw $at, 12($k0) + sw $gp, 80($k0) + sw $sp, 84($k0) + sw $fp, 88($k0) + + sw $k1, 108($k0) + lw $k1, -0x190($zero) + sw $k1, 104($k0) // Real $k0 + + lw $k1, -0x188($zero) + sw $k1, 92($k0) // Real $ra + sw $v0, 16($k0) + sw $v1, 20($k0) sw $a0, 24($k0) sw $a1, 28($k0) sw $a2, 32($k0) @@ -208,23 +153,14 @@ save_args: sw $t7, 68($k0) sw $t8, 72($k0) sw $t9, 76($k0) - sw $gp, 80($k0) - j $ra + mfhi $v0 + mflo $v1 + sw $v0, 96($k0) + sw $v1, 100($k0) -run_idle: - move $k0, $a0 - move $k1, $gp - // Prepare enabling interrupts and switching to user mode. - // The command is executed in the delay slot of the jump. - li $t0, 0xff11 - // Now it's acceptable to receive an exception. Jump to kuseg, - // thereby generating a tlb_refill exception (which is handled). - // The address is the virtual address where the idle task is. - la $t9, ((0x294 << 20) + (0x290 << 10) + 0x288) + lw $gp, -0x184($zero) + la $sp, kernel_stack + KERNEL_STACK_SIZE + move $t9, $ra + la $ra, kernel_exit jr $t9 - mtc0 $t0, $Status - -kernel_exit: - move $k0, $v0 - restore_regs - eret + move $a0, $k0 diff --git a/init.ccp b/init.ccp new file mode 100644 index 0000000..d0dfea7 --- /dev/null +++ b/init.ccp @@ -0,0 +1,125 @@ +#pypp 0 +#include "kernel.hh" + +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 (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)) + + // 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") + // Get number of tlb entries (is 31). + unsigned num; + __asm__ volatile ("mfc0 %0, $16, 1" : "=r"(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)) + // 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)) + __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)) + __asm__ volatile ("tlbwr") + // Allow eret to be used to jump to the idle task. + // 14 is EPC. + __asm__ volatile ("mtc0 %0, $14" :: "r"(0x284a0288)) + // Enable all interrupts and say we're handling an exception. + // 12 is Status. + __asm__ volatile ("mtc0 %0, $12" :: "r"(0x1000ff13)) + +/// 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 + // TOOO: set up initial threads. + + // Done; return to user space (the idle task). + __asm__ volatile ("eret") diff --git a/interrupts.ccp b/interrupts.ccp index 9bbf651..fc12803 100644 --- a/interrupts.ccp +++ b/interrupts.ccp @@ -2,7 +2,7 @@ #include "kernel.hh" // hi and lo cannot be saved in assemply due to space restrictions. -#define save_hilo(x) do { __asm__ ("mfhi %0 ; mflo %1" : "=r"((x)->cpu.hi), "=r"((x)->cpu.lo)); } while (0) +#define save_hilo(x) do { __asm__ volatile ("mfhi %0 ; mflo %1" : "=r"((x)->cpu.hi), "=r"((x)->cpu.lo)); } while (0) /// A TLB miss has occurred. This should eventually move to entry.S. Thread *tlb_refill (Thread *current, unsigned EntryHi): @@ -29,7 +29,7 @@ Thread *tlb_refill (Thread *current, unsigned EntryHi): low1 = page1->physical | 0x18 | 0x4 | 0x2 else low1 = 0 - __asm__ ("mtc0 %0, $2; mtc0 %1, $3; tlbwr" :: "r"(low0), "r"(low1)) + __asm__ volatile ("mtc0 %0, $2; mtc0 %1, $3; tlbwr" :: "r"(low0), "r"(low1)) return current /// An interrupt which is not an exception has occurred. @@ -49,67 +49,3 @@ Thread *cache_error (Thread *current): save_hilo (current) panic (0x33333333, "cache error") return current - -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 - -/// 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; (unsigned)next - 0x80000000 < (1 << 27); p = next, next = (FreePage *)((unsigned)p + 1 << 12): - p->next = next - ++count - p->next = NULL - // 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 - // TOOO: set up initial threads. diff --git a/panic.ccp b/panic.ccp index bfba871..bc85cd7 100644 --- a/panic.ccp +++ b/panic.ccp @@ -4,7 +4,7 @@ void panic (unsigned n, char const *message): while (1): for unsigned bit = 0x80000000; bit; bit >>= 1: - for int i = 0; i < 60000; ++i: - led (n & bit, i > 20000 && i < 40000) - for int i = 0; i < 100000; ++i: + for int i = 0; i < 600000; ++i: + led (n & bit, i > 200000 && i < 400000) + for int i = 0; i < 1000000; ++i: led (false, false) diff --git a/start.S b/start.S deleted file mode 100644 index 5d83a4d..0000000 --- a/start.S +++ /dev/null @@ -1,24 +0,0 @@ - .set noreorder - .globl __start - .globl kernel_stack -__start: - bal 1f - nop - .word _gp -1: lw $gp, 0($ra) - nop - - la $a0, _edata - la $a1, _end -1: sw $zero, 0($a0) - bne $a1, $a0, 1b - addu $a0, 4 - - la $sp, kernel_stack + KERNEL_STACK_SIZE - - bal kernel_entry - nop - b . - nop - - .lcomm kernel_stack, KERNEL_STACK_SIZE