1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-12-29 01:51:08 +02:00
This commit is contained in:
Bas Wijnen 2009-05-14 20:31:47 +02:00
parent aee799648f
commit 5d9d12b860
8 changed files with 269 additions and 248 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
all
all.raw
all.raw.gz
report
uimage

View File

@ -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

45
boot.S Normal file
View File

@ -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

234
entry.S
View File

@ -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

125
init.ccp Normal file
View File

@ -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")

View File

@ -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.

View File

@ -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)

24
start.S
View File

@ -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