1
0
mirror of git://projects.qi-hardware.com/iris.git synced 2024-11-16 21:23:42 +02:00

initial commit

This commit is contained in:
Bas Wijnen 2009-05-11 00:28:12 +02:00
commit aee799648f
9 changed files with 584 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
all
all.raw.gz
report
uimage
*.o

43
Makefile Normal file
View File

@ -0,0 +1,43 @@
load = 0xa0000000
CXXFLAGS = -Wno-unused-parameter -fno-strict-aliasing -fno-builtin -nostdinc
CPPFLAGS = -O5 -Wa,-mips32
CROSS = mipsel-linux-gnu-
CC = $(CROSS)gcc
LD = $(CROSS)ld
OBJCOPY = $(CROSS)objcopy
OBJDUMP = $(CROSS)objdump
BUILT_SOURCES = interrupts.cc panic.cc data.cc test.cc
PYPP = /usr/bin/pypp
%.cc: %.ccp kernel.hh
$(PYPP) --name $< < $< > $@
%.hh: %.hhp
$(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'
%.o:%.cc Makefile kernel.hh
$(CC) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
%.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))
$(LD) --omagic -Ttext $(load) $^ -o $@
junk = mdebug.abi32 reginfo comment pdr
%.raw: %
$(OBJCOPY) -S $(addprefix --remove-section=.,$(junk)) -Obinary $< $@
%.gz: %
gzip < $< > $@
clean:
rm -f all uimage *.o all.raw.gz
.PHONY: clean

8
data.ccp Normal file
View File

@ -0,0 +1,8 @@
#pypp 0
#define EXTERN
#include "kernel.hh"
// This is needed to make gcc happy to compile c++ code without
// its standard library.
char __gxx_personality_v0[] = "hack";

230
entry.S Normal file
View File

@ -0,0 +1,230 @@
// 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
// TODO: this should probably be assembly-only for speed reasons
li $a0, 0xffff0000
la $t9, panic
jr $t9
save_regs
mfc0 $a1, $EntryHi
la $t9, tlb_refill
jr $t9
nop
.fill 0x100 - (. - addr_000)
addr_100:
// Cache error
// TODO
li $a0, 0xaaaa0000
la $t9, panic
jr $t9
save_regs
la $t9, cache_error
jr $t9
nop
.fill 0x180 - (. - addr_000)
addr_180:
// General exception
// TODO
li $a0, 0xaaff0000
la $t9, panic
jr $t9
save_regs
la $t9, exception
jr $t9
nop
.fill 0x200 - (. - addr_000)
addr_200:
// Interrupt
// TODO
li $a0, 0x0a0f0000
la $t9, panic
jr $t9
save_regs
la $t9, interrupt
jr $t9
nop
.fill 0x280 - (. - addr_000)
// space for save_regs.
.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
nop
sw $gp, -12($zero)
save_args:
sw $a0, 24($k0)
sw $a1, 28($k0)
sw $a2, 32($k0)
sw $a3, 36($k0)
sw $t1, 44($k0)
sw $t2, 48($k0)
sw $t3, 52($k0)
sw $t4, 56($k0)
sw $t5, 60($k0)
sw $t6, 64($k0)
sw $t7, 68($k0)
sw $t8, 72($k0)
sw $t9, 76($k0)
sw $gp, 80($k0)
j $ra
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)
jr $t9
mtc0 $t0, $Status
kernel_exit:
move $k0, $v0
restore_regs
eret

115
interrupts.ccp Normal file
View File

@ -0,0 +1,115 @@
#pypp 0
#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)
/// A TLB miss has occurred. This should eventually move to entry.S.
Thread *tlb_refill (Thread *current, unsigned EntryHi):
save_hilo (current)
led (false, false)
Page ***dir = current->address_space->cpu.directory
if !dir:
panic (0x00000000, "no page directory for thread")
EntryHi >>= 12
Page **table = dir[EntryHi >> 10]
if !table:
panic (0x11111111, "no page table at requested address")
EntryHi &= (1 << 10) - 1
Page *page0 = table[EntryHi & ~1]
Page *page1 = table[EntryHi | 1]
if (!(EntryHi & 1) && !page0) || ((EntryHi & 1) && !page1):
panic (0x22222222, "no page mapped at requested address")
unsigned low0, low1
if page0:
low0 = page0->physical | 0x18 | 0x4 | 0x2
else
low0 = 0
if page1:
low1 = page1->physical | 0x18 | 0x4 | 0x2
else
low1 = 0
__asm__ ("mtc0 %0, $2; mtc0 %1, $3; tlbwr" :: "r"(low0), "r"(low1))
return current
/// An interrupt which is not an exception has occurred.
Thread *interrupt (Thread *current):
save_hilo (current)
led (false, false)
return current
/// A general exception has occurred.
Thread *exception (Thread *current):
save_hilo (current)
panic (0xdeadbeaf, "exception")
return current
/// There's a cache error. Big trouble. Probably not worth trying to recover.
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.

75
kernel.hhp Normal file
View File

@ -0,0 +1,75 @@
#pypp 0
#ifndef _KERNEL_HH
#define _KERNEL_HH
#define NULL 0
class Object
class Page
class Thread
class Memory
struct Object:
unsigned size
Object *prev, *next
struct Page : public Object:
Page *page_prev, *page_next
unsigned physical
struct Thread : public Object:
struct Cpu:
unsigned at, v0, v1, a0, a1, a2, a3
unsigned t0, t1, t2, t3, t4, t5, t6, t7, t8, t9
unsigned gp, sp, fp, ra, hi, lo, k0, k1, pc
Cpu cpu
Thread *thread_prev, *thread_next
Thread *schedule_prev, *schedule_next
Memory *address_space
struct Memory : public Object:
Memory *memory_prev, *memory_next
Page *pages
Thread *threads
Memory *memories
unsigned limit, used
struct Cpu:
unsigned asid
Page ***directory
Cpu cpu
// Functions which can be called from assembly must not be mangled.
extern "C":
// Kernel entry points, called from entry.S.
void init ()
Thread *interrupt (Thread *current)
Thread *cache_error (Thread *current)
Thread *exception (Thread *current)
// tlb stuff. tlb_refill is also an entry point.
void tlb_setup ()
Thread *tlb_refill (Thread *current, unsigned EntryHi)
// Start running the idle task for the first time.
void run_idle (Thread *self)
// Panic. n is sent over caps led. message is currently ignored.
void panic (unsigned n, char const *message)
// Debug: switch caps led
void led (bool on, bool tick)
#ifndef EXTERN
#define EXTERN extern
#endif
struct FreePage:
FreePage *next
EXTERN FreePage *zero_pages, *junk_pages
EXTERN Memory top_memory
EXTERN Thread *sleepers, *runners
EXTERN Thread idle
EXTERN Memory idle_memory
EXTERN Page idle_page
#endif

10
panic.ccp Normal file
View File

@ -0,0 +1,10 @@
#pypp 0
#include "kernel.hh"
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:
led (false, false)

24
start.S Normal file
View File

@ -0,0 +1,24 @@
.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

74
test.ccp Normal file
View File

@ -0,0 +1,74 @@
#pypp 0
#include "kernel.hh"
#define REG32(addr) *((volatile unsigned int *)(addr))
#define GPIO_BASE 0xB0010000
#define __gpio_port_data(p) ( REG_GPIO_GPDR(p) )
#define GPIO_GPSLR(n) (GPIO_BASE + (0x10 + (n)*0x30))
#define GPIO_GPSUR(n) (GPIO_BASE + (0x14 + (n)*0x30))
#define GPIO_GPFLR(n) (GPIO_BASE + (0x18 + (n)*0x30))
#define GPIO_GPFUR(n) (GPIO_BASE + (0x1c + (n)*0x30))
#define GPIO_GPDR(n) (GPIO_BASE + (0x00 + (n)*0x30))
#define REG_GPIO_GPSLR(n) REG32(GPIO_GPSLR((n)))
#define REG_GPIO_GPSUR(n) REG32(GPIO_GPSUR((n)))
#define REG_GPIO_GPFLR(n) REG32(GPIO_GPFLR((n)))
#define REG_GPIO_GPFUR(n) REG32(GPIO_GPFUR((n)))
#define REG_GPIO_GPDR(n) REG32(GPIO_GPDR((n)))
static void __gpio_port_as_gpiofn (unsigned p, unsigned o, unsigned fn):
unsigned int tmp;
if o < 16:
tmp = REG_GPIO_GPSLR(p)
tmp &= ~(3 << ((o) << 1))
REG_GPIO_GPSLR(p) = tmp
tmp = REG_GPIO_GPFLR(p)
tmp &= ~(3 << ((o) << 1))
tmp |= fn << ((o) << 1)
REG_GPIO_GPFLR(p) = tmp
else:
tmp = REG_GPIO_GPSUR(p)
tmp &= ~(3 << (((o) - 16) << 1))
REG_GPIO_GPSUR(p) = tmp
tmp = REG_GPIO_GPFUR(p)
tmp &= ~(3 << (((o) - 16) << 1))
tmp |= fn << (((o) - 16) << 1)
REG_GPIO_GPFUR(p) = tmp
static void __gpio_port_as_output (unsigned p, unsigned o):
__gpio_port_as_gpiofn (p, o, 1)
static void __gpio_port_as_input (unsigned p, unsigned o):
__gpio_port_as_gpiofn (p, o, 0)
static void __gpio_as_output (unsigned n):
__gpio_port_as_output(n / 32, n % 32)
static void __gpio_as_input (unsigned n):
__gpio_port_as_input(n / 32, n % 32)
static void __gpio_set_pin (unsigned n):
__gpio_port_data (n / 32) |= (1 << (n % 32))
static void __gpio_clear_pin (unsigned n):
__gpio_port_data (n / 32) &= ~(1 << (n % 32))
#define CAPSLOCKLED_IO 27
#define NUMLOCKLED_IO 86
#define NETWORK_IO 9
#define LIGHT 105
void led (bool on, bool tick):
__gpio_as_output (CAPSLOCKLED_IO)
__gpio_as_output (NUMLOCKLED_IO)
__gpio_as_output (NETWORK_IO)
if on:
__gpio_set_pin (NUMLOCKLED_IO)
__gpio_clear_pin (CAPSLOCKLED_IO)
else:
__gpio_set_pin (CAPSLOCKLED_IO)
__gpio_clear_pin (NUMLOCKLED_IO)
if tick:
__gpio_clear_pin (NETWORK_IO)
else:
__gpio_set_pin (NETWORK_IO)