URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [arch/] [ppc/] [kernel/] [head.S] - Rev 1765
Compare with Previous | Blame | View Log
#include "ppc_asm.tmpl"
#include "ppc_defs.h"
#include <linux/errno.h>
#define NEWMM
#define SYNC() \
isync; \
sync
/* #define TLB_STATS */
/* Keep track of low-level exceptions - rather crude, but informative */
#define STATS
/*
* Increment a [64 bit] statistic counter
* Uses R2, R3
*/
#define BUMP(ctr) \
lis r2,ctr@h; \
ori r2,r2,ctr@l; \
lwz r3,4(r2); \
addic r3,r3,1; \
stw r3,4(r2); \
lwz r3,0(r2); \
addze r3,r3; \
stw r3,0(r2)
/* The same as 'BUMP' but running unmapped (TLB code) */
#define BUMP_UNMAPPED(ctr) \
mfspr r0,XER; \
lis r2,ctr@h; \
ori r2,r2,ctr@l; \
lis r3,0xF000; \
andc r2,r2,r3; \
lwz r3,4(r2); \
addic r3,r3,1; \
stw r3,4(r2); \
lwz r3,0(r2); \
addze r3,r3; \
mtspr XER,r0; \
stw r3,0(r2)
/* These macros can be used to generate very raw traces of low-level */
/* operations (where printf, etc. can't help). All they provide is */
/* some after-the-fact documentation of what took place. Since [in */
/* most instances] they have no registers to work with, they use the */
/* hardware "special" registers SPRx for storage. Because of this, */
/* defining more than one of them simultaneously will yield incorrect */
/* results and a non-functional system. Note: the trick here is to */
/* gather some data without disturbing anything - Heisenberg are you watching? */
/* CAUTION! Don't turn on more than one of these at once! */
/* #define DO_TRAP_TRACE */
/* #define DO_TLB_TRACE */
/* #define DO_RFI_TRACE */
#ifdef DO_RFI_TRACE
#define DO_RFI_TRACE_UNMAPPED(mark) \
mtspr SPR0,r1; \
mtspr SPR1,r2; \
mtspr SPR2,r3; \
mfcr r3; \
mtspr SPR3,r3; \
lis r1,_RFI_ptr@h; \
ori r1,r1,_RFI_ptr@l; \
lis r3,0xF000; \
andc r1,r1,r3; \
lwz r1,0(r1); \
andc r1,r1,r3; \
subi r1,r1,4; \
lis r2,(mark>>16); \
ori r2,r2,(mark&0xFFFF); \
stwu r2,4(r1); \
mfspr r2,SRR0; \
stwu r2,4(r1); \
mfspr r2,SRR1; \
stwu r2,4(r1); \
addi r1,r1,4+4; \
lis r2,_RFI_ptr@h; \
ori r2,r2,_RFI_ptr@l; \
andc r2,r2,r3; \
stw r1,0(r2); \
mfspr r3,SPR3; \
mtcrf 0xFF,r3; \
mfspr r1,SPR0; \
mfspr r2,SPR1; \
mfspr r3,SPR2
#define DO_RFI_TRACE_MAPPED(mark) \
mtspr SPR0,r1; \
mtspr SPR1,r2; \
mtspr SPR2,r3; \
mfcr r3; \
mtspr SPR3,r3; \
lis r1,_RFI_ptr@h; \
ori r1,r1,_RFI_ptr@l; \
lwz r1,0(r1); \
lis r3,0x9000; \
or r1,r1,r3; \
subi r1,r1,4; \
lis r2,(mark>>16); \
ori r2,r2,(mark&0xFFFF); \
stwu r2,4(r1); \
mfspr r2,SRR0; \
stwu r2,4(r1); \
mfspr r2,SRR1; \
stwu r2,4(r1); \
addi r1,r1,4+4; \
lis r2,_RFI_ptr@h; \
ori r2,r2,_RFI_ptr@l; \
stw r1,0(r2); \
mfspr r3,SPR3; \
mtcrf 0xFF,r3; \
mfspr r1,SPR0; \
mfspr r2,SPR1; \
mfspr r3,SPR2
#else
#define DO_RFI_TRACE_UNMAPPED(mark)
#define DO_RFI_TRACE_MAPPED(mark)
#endif
#ifdef DO_TRAP_TRACE
#define DEFAULT_TRAP(offset) \
mtspr SPR0,r1; \
mtspr SPR1,r2; \
mtspr SPR2,r3; \
lis r1,_TRAP_ptr@h; \
ori r1,r1,_TRAP_ptr@l; \
lis r3,0xF000; \
andc r1,r1,r3; \
lwz r1,0(r1); \
andc r1,r1,r3; \
subi r1,r1,4; \
lis r2,0xCACA; \
ori r2,r2,offset; \
stwu r2,4(r1); \
mfspr r2,SRR0; \
stwu r2,4(r1); \
mfspr r2,SRR1; \
stwu r2,4(r1); \
mfspr r2,SPR0; \
stwu r2,4(r1); \
addi r1,r1,4; \
lis r2,_TRAP_ptr@h; \
ori r2,r2,_TRAP_ptr@l; \
andc r2,r2,r3; \
stw r1,0(r2); \
mfspr r1,SPR0; \
mfspr r2,SPR1; \
mfspr r3,SPR2; \
li r13,0; \
ori r13,r13,HID0_ICE; \
mtspr HID0,r13; \
lis r13,0xFFF00000>>16; \
ori r13,r13,offset; \
mtlr r13; \
b hang
#define TRACE_TRAP(offset) \
mtspr SPR0,r1; \
mtspr SPR1,r2; \
mtspr SPR2,r3; \
mfcr r3; \
mtspr SPR3,r3; \
lis r1,_TRAP_ptr@h; \
ori r1,r1,_TRAP_ptr@l; \
lis r3,0xF000; \
andc r1,r1,r3; \
lwz r1,0(r1); \
andc r1,r1,r3; \
subi r1,r1,4; \
lis r2,0xCABB; \
ori r2,r2,offset; \
stwu r2,4(r1); \
dcbst 0,r1; \
mfspr r2,SRR0; \
stwu r2,4(r1); \
dcbst 0,r1; \
mfspr r2,SRR1; \
stwu r2,4(r1); \
dcbst 0,r1; \
li r2,offset; \
cmpi 0,r2,0x0C00; \
beq 01f; \
cmpi 0,r2,0x0300; \
beq 00f; \
cmpi 0,r2,0x0400; \
beq 00f; \
mfspr r2,SPR0; \
b 02f; \
00: mfspr r2,DAR; \
b 02f; \
01: mr r2,r0; \
02: stwu r2,4(r1); \
dcbst 0,r1; \
addi r1,r1,4; \
mflr r2; \
stw r2,0(r1); \
bl check_trace; \
lwz r2,0(r1); \
mtlr r2; \
02: lis r2,_TRAP_ptr@h; \
ori r2,r2,_TRAP_ptr@l; \
oris r1,r1,0x9000; \
cmp 0,r1,r2; \
bne 00f; \
lis r1,_TRAP_TRACE@h; \
ori r1,r1,_TRAP_TRACE@l; \
00: lis r3,0xF000; \
andc r2,r2,r3; \
stw r1,0(r2); \
mfspr r1,SPR0; \
mfspr r2,SPR1; \
mfspr r3,SPR3; \
mtcrf 0xFF,r3; \
mfspr r3,SPR2
#else
#define DEFAULT_TRAP(offset) \
li r13,0; \
ori r13,r13,HID0_ICE; \
mtspr HID0,r13; \
lis r13,0xFFF00000>>16; \
ori r13,r13,offset; \
mtlr r13; \
blr
#define TRACE_TRAP(offset)
#endif
#define DATA_CACHE_OFF() \
mfspr r2,HID0; \
li r3,0; \
ori r3,r3,HID0_DCE; \
andc r2,r2,r3; \
mtspr HID0,r2;
#define DATA_CACHE_ON() \
mfspr r2,HID0; \
ori r2,r2,HID0_DCE; \
mtspr HID0,r2;
/* This instruction is not implemented on the PPC 603 */
#define tlbia \
li r4,64; \
mtspr CTR,r4; \
lis r4,0x9000; \
0: tlbie r4; \
addi r4,r4,0x1000; \
bdnz 0b
/* Validate kernel stack - check for overflow */
#define CHECK_STACK()
#define _CHECK_STACK() \
mtspr SPR0,r3; \
lis r2,current_set@ha; \
lwz r2,current_set@l(r2); \
lwz r2,KERNEL_STACK_PAGE(r2); \
lis r3,sys_stack@h; \
ori r3,r3,sys_stack@l; \
cmpl 0,r1,r3; \
ble 02f; \
li r3,0x0FFF; \
andc r2,r2,r3; \
andc r3,r1,r3; \
cmp 0,r3,r2; \
beq 02f; \
mr r3,r1; \
bl _EXTERN(bad_stack); \
02: mfspr r3,SPR0
/* Save all registers on kernel stack during an exception */
#define SAVE_REGS(mark) \
subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
stmw r3,GPR3(r1); /* Save R3..R31 */ \
stw r3,ORIG_GPR3(r1); \
stw r0,GPR0(r1); \
mfspr r2,SPR0; \
stw r2,GPR1(r1); \
mfspr r2,SPR1; \
stw r2,GPR2(r1); \
mfspr r2,SPR2; \
stw r2,_NIP(r1); \
mfspr r2,SPR3; \
stw r2,_MSR(r1); \
mfctr r2; \
stw r2,_CTR(r1); \
mflr r2; \
stw r2,_LINK(r1); \
mfcr r2; \
stw r2,_CCR(r1); \
mfspr r2,XER; \
stw r2,_XER(r1); \
stfd fr0,FPR0(r1); \
stfd fr1,FPR1(r1); \
stfd fr2,FPR2(r1); \
stfd fr3,FPR3(r1); \
mffs fr0; \
stfd fr0,FPCSR(r1); \
lis r2,_break_lwarx@h; \
ori r2,r2,_break_lwarx@l; \
stwcx. r2,0,r2; \
li r2,mark; \
stw r2,TRAP(r1); \
lis r2,0xDEAD; \
ori r2,r2,0xDEAD; \
stw r2,MARKER(r1); \
li r2,0; \
stw r2,RESULT(r1)
#define SAVE_PAGE_FAULT_REGS(offset) \
mfspr r2,DAR; \
stw r2,_DAR(r1); \
mfspr r2,DSISR; \
stw r2,_DSISR(r1); \
mfspr r2,PVR; /* Check for 603/603e */ \
srwi r2,r2,16; \
cmpi 0,r2,3; /* 603 */ \
beq 22f; \
cmpi 0,r2,6; /* 603e */ \
bne 24f; \
22: mfspr r2,HASH1; /* Note: these registers exist only on 603 */ \
stw r2,_HASH1(r1); \
mfspr r2,HASH2; \
stw r2,_HASH2(r1); \
mfspr r2,IMISS; \
stw r2,_IMISS(r1); \
mfspr r2,DMISS; \
stw r2,_DMISS(r1); \
mfspr r2,ICMP; \
stw r2,_ICMP(r1); \
mfspr r2,DCMP; \
stw r2,_DCMP(r1); \
24:
#define SAVE_INT_REGS(mark) \
mtspr SPR0,r1; /* Save current stack pointer */ \
mtspr SPR1,r2; /* Scratch */ \
mfcr r2; \
mtspr SPR2,r2; \
mfspr r2,SRR1; /* Interrupt from user/system mode */ \
andi. r2,r2,MSR_PR; \
beq+ 10f; /* Jump if system - already have stack */ \
mfspr r2,SPR2; /* Restore CCR */ \
mtcrf 0xFF,r2; \
mfspr r2,SRR0; /* Preserve interrupt registers */ \
mtspr SPR2,r2; \
mfspr r2,SRR1; \
mtspr SPR3,r2; \
lis r2,05f@h; \
ori r2,r2,05f@l; \
mtspr SRR0,r2; \
mfmsr r2; \
ori r2,r2,MSR_|MSR_DR|MSR_IR; \
mtspr SRR1,r2; \
rfi; \
05: lis r2,current_set@ha; \
lwz r2,current_set@l(r2); \
mfspr r1,SPR2; \
stw r1,TSS+LAST_PC(r2); \
mfspr r1,SPR0; \
stw r1,TSS+USER_STACK(r2); \
lwz r1,TSS+KSP(r2); \
subi r1,r1,INT_FRAME_SIZE; /* Make room for frame */ \
stw r1,TSS+PT_REGS(r2); /* Save regs pointer for 'ptrace' */ \
lwz r1,TSS+KSP(r2); \
b 20f; \
10: mfspr r2,SPR2; /* Restore CCR */ \
mtcrf 0xFF,r2; \
mfspr r2,SRR0; /* Preserve interrupt registers */ \
mtspr SPR2,r2; \
mfspr r2,SRR1; \
mtspr SPR3,r2; \
lis r2,20f@h; \
ori r2,r2,20f@l; \
mtspr SRR0,r2; \
mfmsr r2; \
ori r2,r2,MSR_|MSR_DR|MSR_IR; \
mtspr SRR1,r2; \
SYNC(); \
rfi; \
20: SAVE_REGS(mark); \
CHECK_STACK()
#define RETURN_FROM_INT(mark) \
90: mfmsr r0; /* Disable interrupts */ \
li r4,0; \
ori r4,r4,MSR_EE; \
andc r0,r0,r4; \
sync; /* Some chip revs need this... */ \
mtmsr r0; \
lis r2,intr_count@ha; /* Need to run 'bottom half' */ \
lwz r3,intr_count@l(r2); \
cmpi 0,r3,0; \
bne 00f; \
lis r4,bh_mask@ha; \
lwz r4,bh_mask@l(r4); \
lis r5,bh_active@ha; \
lwz r5,bh_active@l(r5); \
and. r4,r4,r5; \
beq 00f; \
addi r3,r3,1; \
stw r3,intr_count@l(r2); \
bl _EXTERN(_do_bottom_half); \
lis r2,intr_count@ha; \
lwz r3,intr_count@l(r2); \
subi r3,r3,1; \
stw r3,intr_count@l(r2); \
00: lwz r2,_MSR(r1); /* Returning to user mode? */ \
andi. r2,r2,MSR_PR; \
beq+ 10f; /* no - no need to mess with stack */ \
/* lis r2,kernel_pages_are_copyback@ha; \
lwz r2,kernel_pages_are_copyback@l(r2); \
cmpi 0,r2,0; \
beq 05f; \
bl _EXTERN(flush_instruction_cache); */ \
05: lis r3,current_set@ha; /* need to save kernel stack pointer */ \
lwz r3,current_set@l(r3); \
addi r4,r1,INT_FRAME_SIZE; /* size of frame */ \
stw r4,TSS+KSP(r3); \
lwz r4,STATE(r3); /* If state != 0, can't run */ \
cmpi 0,r4,0; \
beq 06f; \
bl _EXTERN(schedule); \
b 90b; \
06: lwz r4,COUNTER(r3); /* Time quantum expired? */ \
cmpi 0,r4,0; \
bne 07f; \
bl _EXTERN(schedule); \
b 90b; \
07: lwz r4,BLOCKED(r3); /* Check for pending unblocked signals */ \
lwz r5,SIGNAL(r3); \
andc. r0,r5,r4; /* Lets thru any unblocked */ \
beq 10f; \
mr r3,r4; \
mr r4,r1; \
bl _EXTERN(do_signal); \
10: lwz r2,_NIP(r1); /* Restore environment */ \
mtspr SRR0,r2; \
lwz r2,_MSR(r1); \
mtspr SRR1,r2; \
lmw r3,GPR3(r1); \
lwz r2,_CTR(r1); \
mtctr r2; \
lwz r2,_LINK(r1); \
mtlr r2; \
lwz r2,_XER(r1); \
mtspr XER,r2; \
lwz r2,_CCR(r1); \
mtcrf 0xFF,r2; \
lfd fr0,FPCSR(r1); \
mtfsf 0xFF,fr0; \
lfd fr0,FPR0(r1); \
lfd fr1,FPR1(r1); \
lfd fr2,FPR2(r1); \
lfd fr3,FPR3(r1); \
lwz r0,GPR0(r1); \
lwz r2,GPR2(r1); \
lwz r1,GPR1(r1); \
SYNC(); \
rfi
_TEXT()
/*
* This code may be executed by a bootstrap process. If so, the
* purpose is to relocate the loaded image to it's final location
* in memory.
* R3: End of image
* R4: Start of image - 0x400
* R11: Start of command line string
* R12: End of command line string
* R30: 'BeBx' if this is a BeBox
*
*/
.globl _start
.globl _stext
_stext:
_start:
addi r4,r4,0x400 /* Point at start of image */
li r5,0 /* Load address */
subi r4,r4,4 /* Adjust for auto-increment */
subi r5,r5,4
subi r3,r3,4
00: lwzu r0,4(r4) /* Fast move */
stwu r0,4(r5)
cmp 0,r3,r4
bne 00b
li r5,0x100 /* Actual code starts here */
mtlr r5
blr
hang:
ori r0,r0,0
b hang
/*
* BeBox CPU #1 vector & code
*/
_ORG(0x0080)
.globl BeBox_CPU1_vector
BeBox_CPU1_vector:
.long 0
BeBox_CPU1_reset:
li r1,BeBox_CPU1_vector@l
li r2,0
stw r2,0(r1)
00: lwz r2,0(r1)
cmpi 0,r2,0
bne 10f
li r2,10000
mtctr r2
02: nop
bdnz 02b
b 00b
10: mtlr r1
blr
_ORG(0x0100)
/* Hard Reset */
.globl HardReset
HardReset:
b Reset
_ORG(0x0200)
b MachineCheck
_ORG(0x0300)
b DataAccess
_ORG(0x0400)
b InstructionAccess
_ORG(0x0500)
b HardwareInterrupt
_ORG(0x0600)
b Alignment
_ORG(0x0700)
b ProgramCheck
_ORG(0x0800)
b FloatingPointCheck
/* Decrementer register - ignored for now... */
_ORG(0x0900)
/* TRACE_TRAP(0x900) */
mtspr SPR0,r1
lis r1,0x7FFF
ori r1,r1,0xFFFF
mtspr DEC,r1
mfspr r1,SPR0
#if 0
SYNC
#endif
rfi
_ORG(0x0A00)
DEFAULT_TRAP(0x0A00)
_ORG(0x0B00)
DEFAULT_TRAP(0x0B00)
/*
* System call
*/
_ORG(0x0C00)
b SystemCall
_ORG(0x0D00)
b SingleStep
_ORG(0x0E00)
DEFAULT_TRAP(0x0E00)
_ORG(0x0F00)
DEFAULT_TRAP(0x0F00)
/*
* Handle TLB Miss on an instruction load
*/
_ORG(0x1000)
/* Note: It is *unsafe* to use the TRACE TRAP macro here since there */
/* could be a 'trace' in progress when the TLB miss occurs. */
/* TRACE_TRAP(0x1000) */
#ifdef TLB_STATS
lis r2,DataLoadTLB_trace_ptr@h
ori r2,r2,DataLoadTLB_trace_ptr@l
lis r3,0xF000
andc r2,r2,r3
lwz r1,0(r2)
andc r1,r1,r3
li r0,0x1000
stw r0,0(r1)
mftbu r0
stw r0,4(r1)
mftb r0
stw r0,8(r1)
mfspr r0,IMISS
mfspr r3,SRR1
extrwi r3,r3,1,14
or r0,r0,r3
stw r0,12(r1)
addi r1,r1,16
mfcr r0
cmpl 0,r1,r2
blt 00f
lis r1,DataLoadTLB_trace_buf@h
ori r1,r1,DataLoadTLB_trace_buf@l
lis r3,0xF000
andc r1,r1,r3
00: mtcrf 0xFF,r0
stw r1,0(r2)
#endif
b InstructionTLBMiss
/*
* Handle TLB Miss on a data item load
*/
_ORG(0x1100)
/* TRACE_TRAP(0x1100) */
#ifdef TLB_STATS
lis r2,DataLoadTLB_trace_ptr@h
ori r2,r2,DataLoadTLB_trace_ptr@l
lis r3,0xF000
andc r2,r2,r3
lwz r1,0(r2)
andc r1,r1,r3
li r0,0x1100
stw r0,0(r1)
mftbu r0
stw r0,4(r1)
mftb r0
stw r0,8(r1)
mfspr r0,DMISS
mfspr r3,SRR1
extrwi r3,r3,1,14
or r0,r0,r3
stw r0,12(r1)
addi r1,r1,16
mfcr r0
cmpl 0,r1,r2
blt 00f
lis r1,DataLoadTLB_trace_buf@h
ori r1,r1,DataLoadTLB_trace_buf@l
lis r3,0xF000
andc r1,r1,r3
00: mtcrf 0xFF,r0
stw r1,0(r2)
.data
DataLoadTLB_trace_buf:
.space 64*1024*4
DataLoadTLB_trace_ptr:
.long DataLoadTLB_trace_buf
.text
#endif
b DataLoadTLBMiss
/*
* Handle TLB Miss on a store operation
*/
_ORG(0x1200)
/* TRACE_TRAP(0x1200) */
#ifdef TLB_STATS
lis r2,DataLoadTLB_trace_ptr@h
ori r2,r2,DataLoadTLB_trace_ptr@l
lis r3,0xF000
andc r2,r2,r3
lwz r1,0(r2)
andc r1,r1,r3
li r0,0x1200
stw r0,0(r1)
mftbu r0
stw r0,4(r1)
mftb r0
stw r0,8(r1)
mfspr r0,DMISS
mfspr r3,SRR1
extrwi r3,r3,1,14
or r0,r0,r3
stw r0,12(r1)
addi r1,r1,16
mfcr r0
cmpl 0,r1,r2
blt 00f
lis r1,DataLoadTLB_trace_buf@h
ori r1,r1,DataLoadTLB_trace_buf@l
lis r3,0xF000
andc r1,r1,r3
00: mtcrf 0xFF,r0
stw r1,0(r2)
#endif
b DataStoreTLBMiss
_ORG(0x1300)
InstructionAddressBreakpoint:
DEFAULT_TRAP(0x1300)
_ORG(0x1400)
SystemManagementInterrupt:
DEFAULT_TRAP(0x1400)
_ORG(0x1500)
/*
* This space [buffer] is used to forceably flush the data cache when
* running in copyback mode. This is necessary IFF the data cache could
* contain instructions for which the instruction cache has stale data.
* Since the instruction cache NEVER snoops the data cache, memory must
* be made coherent with the data cache to insure that the instruction
* cache gets a valid instruction stream. Note that this flushing is
* only performed when switching from system to user mode since this is
* the only juncture [as far as the OS goes] where the data cache may
* contain instructions, e.g. after a disk read.
*/
#define NUM_CACHE_LINES 128*4
#define CACHE_LINE_SIZE 32
cache_flush_buffer:
.space NUM_CACHE_LINES*CACHE_LINE_SIZE /* CAUTION! these need to match hardware */
#if NUM_CACHE_LINES < 512
_ORG(0x4000)
#endif
/*
* Hardware reset [actually from bootstrap]
* Initialize memory management & call secondary init
* Registers initialized by bootstrap:
* R11: Start of command line string
* R12: End of command line string
* R30: 'BeBx' if this is a BeBox
*/
Reset:
lis r7,0xF000 /* To mask upper 4 bits */
#define IS_BE_BOX 0x42654278 /* 'BeBx' */
lis r1,isBeBox@h
ori r1,r1,isBeBox@l
andc r1,r1,r7
/* See if this is a CPU other than CPU#1 */
/* This [currently] happens on the BeBox */
lwz r2,0(r1)
cmpi 0,r2,0
bne Reset_BeBox_CPU1
/* Save machine type indicator */
li r2,0
lis r3,IS_BE_BOX>>16
ori r3,r3,IS_BE_BOX&0xFFFF
cmp 0,r30,r3
bne 00f
li r2,1
mr r11,r28
mr r12,r29
lis r5,BeBox_CPU1_vector@h
ori r5,r5,BeBox_CPU1_vector@l
andc r5,r5,r7 /* Tell CPU #1 where to go */
00: stw r2,0(r1)
stw r30,4(r1)
/* Copy argument string */
li r0,0 /* Null terminate string */
stb r0,0(r12)
lis r1,cmd_line@h
ori r1,r1,cmd_line@l
andc r1,r1,r7 /* No MMU yet - need unmapped address */
subi r1,r1,1
subi r11,r11,1
00: lbzu r0,1(r11)
cmpi 0,r0,0
stbu r0,1(r1)
bne 00b
lis r1,sys_stack@h
ori r1,r1,sys_stack@l
li r2,0x0FFF /* Mask stack address down to page boundary */
andc r1,r1,r2
subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
li r2,0 /* TOC pointer for nanokernel */
li r0,MSR_ /* Make sure FPU enabled */
mtmsr r0
lis r3,_edata@h /* Clear BSS */
ori r3,r3,_edata@l
andc r3,r3,r7 /* make unmapped address */
lis r4,_end@h
ori r4,r4,_end@l
andc r4,r4,r7 /* make unmapped address */
subi r3,r3,4
li r0,0
00: stwu r0,4(r3)
cmp 0,r3,r4
blt 00b
/* Initialize BAT registers */
lis r3,BAT0@h
ori r3,r3,BAT0@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT0U,r0
mtspr DBAT0U,r0
lwz r0,4(r3)
mtspr IBAT0L,r0
mtspr DBAT0L,r0
lis r3,BAT1@h
ori r3,r3,BAT1@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT1U,r0
mtspr DBAT1U,r0
lwz r0,4(r3)
mtspr IBAT1L,r0
mtspr DBAT1L,r0
/* this BAT mapping will cover all of kernel space */
#ifdef NEWMM
lis r3,BAT2@h
ori r3,r3,BAT2@l
#else
lis r3,TMP_BAT2@h
ori r3,r3,TMP_BAT2@l
#endif
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT2U,r0
mtspr DBAT2U,r0
lwz r0,4(r3)
mtspr IBAT2L,r0
mtspr DBAT2L,r0
#if 0
lis r3,BAT3@h
ori r3,r3,BAT3@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT3U,r0
mtspr DBAT3U,r0
lwz r0,4(r3)
mtspr IBAT3L,r0
mtspr DBAT3L,r0
#endif
/* Now we can turn on the MMU */
mfmsr r3
ori r3,r3,MSR_DR|MSR_IR
mtspr SRR1,r3
lis r3,10f@h
ori r3,r3,10f@l
mtspr SRR0,r3
DO_RFI_TRACE_UNMAPPED(0xDEAD0000)
SYNC
rfi /* enables MMU */
10: bl _EXTERN(MMU_init) /* initialize MMU environment */
DO_RFI_TRACE_MAPPED(0xDEAD0100)
/* Withdraw BAT2->RAM mapping */
lis r7,0xF000 /* To mask upper 4 bits */
lis r3,20f@h
ori r3,r3,20f@l
andc r3,r3,r7 /* make unmapped address */
mtspr SRR0,r3
mfmsr r3
li r4,MSR_DR|MSR_IR
andc r3,r3,r4
mtspr SRR1,r3
SYNC
DO_RFI_TRACE_MAPPED(0xDEAD0200)
SYNC
rfi
20:
DO_RFI_TRACE_UNMAPPED(0xDEAD0400)
20: lis r3,BAT2@h
ori r3,r3,BAT2@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT2U,r0
mtspr DBAT2U,r0
lwz r0,4(r3)
mtspr IBAT2L,r0
mtspr DBAT2L,r0
/* Load up the kernel context */
lis r2,init_task@h
ori r2,r2,init_task@l
addi r2,r2,TSS
andc r2,r2,r7 /* make unmapped address */
SYNC /* Force all PTE updates to finish */
tlbia /* Clear all TLB entries */
lis r3,_SDR1@h
ori r3,r3,_SDR1@l
andc r3,r3,r7 /* make unmapped address */
lwz r3,0(r3)
mtspr SDR1,r3
lwz r0,MMU_SEG0(r2)
mtsr SR0,r0
lwz r0,MMU_SEG1(r2)
mtsr SR1,r0
lwz r0,MMU_SEG2(r2)
mtsr SR2,r0
lwz r0,MMU_SEG3(r2)
mtsr SR3,r0
lwz r0,MMU_SEG4(r2)
mtsr SR4,r0
lwz r0,MMU_SEG5(r2)
mtsr SR5,r0
lwz r0,MMU_SEG6(r2)
mtsr SR6,r0
lwz r0,MMU_SEG7(r2)
mtsr SR7,r0
lwz r0,MMU_SEG8(r2)
mtsr SR8,r0
lwz r0,MMU_SEG9(r2)
mtsr SR9,r0
lwz r0,MMU_SEG10(r2)
mtsr SR10,r0
lwz r0,MMU_SEG11(r2)
mtsr SR11,r0
lwz r0,MMU_SEG12(r2)
mtsr SR12,r0
lwz r0,MMU_SEG13(r2)
mtsr SR13,r0
lwz r0,MMU_SEG14(r2)
mtsr SR14,r0
lwz r0,MMU_SEG15(r2)
mtsr SR15,r0
/* Now turn on the MMU for real! */
mfmsr r3
ori r3,r3,MSR_DR|MSR_IR
mtspr SRR1,r3
lis r3,30f@h
ori r3,r3,30f@l
mtspr SRR0,r3
DO_RFI_TRACE_UNMAPPED(0xDEAD0500)
SYNC
rfi /* enables MMU */
30:
/* Turn on L1 Data Cache */
mfspr r3,HID0 /* Caches are controlled by this register */
ori r4,r3,(HID0_ICE|HID0_ICFI)
ori r3,r3,(HID0_ICE)
ori r4,r4,(HID0_DCE|HID0_DCI)
ori r3,r3,(HID0_DCE)
sync
mtspr HID0,r4
mtspr HID0,r3
/* L1 cache enable */
mfspr r2,PVR /* Check for 603/603e */
srwi r2,r2,16
cmpi 0,r2,4 /* 604 */
bne 40f
mfspr r3,HID0 /* Turn on 604 specific features */
ori r3,r3,(HID0_SIED|HID0_BHTE)
mtspr HID0,r3
40: b _EXTERN(start_kernel) /* call main code */
.long 0 # Illegal!
/*
* BeBox CPU #2 runs here
*/
Reset_BeBox_CPU1:
lis r1,CPU1_stack@h
ori r1,r1,CPU1_stack@l
li r2,0x0FFF /* Mask stack address down to page boundary */
andc r1,r1,r2
subi r1,r1,INT_FRAME_SIZE /* Padding for first frame */
lis r30,CPU1_trace@h
ori r30,r30,CPU1_trace@l
andc r30,r30,r7
li r5,1
stw r5,0(r30)
li r2,0 /* TOC pointer for nanokernel */
li r0,MSR_ /* Make sure FPU enabled */
mtmsr r0
/* Initialize BAT registers */
lis r3,BAT0@h
ori r3,r3,BAT0@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT0U,r0
mtspr DBAT0U,r0
lwz r0,4(r3)
mtspr IBAT0L,r0
mtspr DBAT0L,r0
lis r3,BAT1@h
ori r3,r3,BAT1@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT1U,r0
mtspr DBAT1U,r0
lwz r0,4(r3)
mtspr IBAT1L,r0
mtspr DBAT1L,r0
lis r3,TMP_BAT2@h
ori r3,r3,TMP_BAT2@l
andc r3,r3,r7 /* make unmapped address */
lwz r0,0(r3)
mtspr IBAT2U,r0
mtspr DBAT2U,r0
lwz r0,4(r3)
mtspr IBAT2L,r0
mtspr DBAT2L,r0
/* Now we can turn on the MMU */
mfmsr r3
ori r3,r3,MSR_DR|MSR_IR
mtspr SRR1,r3
lis r3,10f@h
ori r3,r3,10f@l
mtspr SRR0,r3
li r5,2
stw r5,0(r30)
SYNC
rfi /* enables MMU */
10:
lis r30,CPU1_trace@h
ori r30,r30,CPU1_trace@l
li r5,3
stw r5,0(r30)
bl _EXTERN(BeBox_CPU1)
/*
* Machine Check (Bus Errors, etc)
*/
MachineCheck:
TRACE_TRAP(0x0200)
SAVE_INT_REGS(0x0200)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(MachineCheckException)
RETURN_FROM_INT(0x0200)
/*
* Data Access exception
*/
DataAccess:
/* TRACE_TRAP(0x0300) */
SAVE_INT_REGS(0x0300)
SAVE_PAGE_FAULT_REGS(0x0300)
BUMP(__Data_Page_Faults)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(DataAccessException)
#if 0
bl _EXTERN(flush_instruction_cache)
#endif
RETURN_FROM_INT(0x0300)
/*
* Instruction Access Exception
*/
InstructionAccess:
/* TRACE_TRAP(0x0400) */
SAVE_INT_REGS(0x0400)
SAVE_PAGE_FAULT_REGS(0x0400)
BUMP(__Instruction_Page_Faults)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(InstructionAccessException)
#if 0
bl _EXTERN(flush_instruction_cache)
#endif
RETURN_FROM_INT(0x0400)
/*
* Hardware Interrupt
*/
HardwareInterrupt:
SAVE_INT_REGS(0x0500)
BUMP(__Hardware_Interrupts)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(handle_IRQ)
RETURN_FROM_INT(0x0500)
/*
* Alignment
*/
Alignment:
TRACE_TRAP(0x0600)
SAVE_INT_REGS(0x0600)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(AlignmentException)
RETURN_FROM_INT(0x0600)
/*
* Illegal instruction
*/
ProgramCheck:
TRACE_TRAP(0x0700)
SAVE_INT_REGS(0x0700)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(ProgramCheckException)
RETURN_FROM_INT(0x0700)
/*
* Single Step Exception
*/
SingleStep:
SAVE_INT_REGS(0x0D00)
SAVE_PAGE_FAULT_REGS(0x0D00)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(SingleStepException)
#if 0
bl _EXTERN(flush_instruction_cache)
#endif
RETURN_FROM_INT(0x0D00)
/*
* Floating point [not available, etc]
*/
FloatingPointCheck:
TRACE_TRAP(0x0800)
SAVE_INT_REGS(0x0800)
mr r3,r1 /* Set pointer to saved regs */
bl _EXTERN(FloatingPointCheckException)
RETURN_FROM_INT(0x0200)
/*
* System Call exception
*/
SystemCall:
/* TRACE_TRAP(0x0C00) */
SAVE_INT_REGS(0x0C00)
lwz r2,_CCR(r1) /* Clear SO bit in CR */
lis r9,0x1000
andc r2,r2,r9
stw r2,_CCR(r1)
cmpi 0,r0,0x7777 /* Special case for 'sys_sigreturn' */
bne+ 10f
mr r3,r1
bl _EXTERN(sys_sigreturn)
cmpi 0,r3,0 /* Check for restarted system call */
bge 99f
b 20f
10: lis r2,current_set@ha
lwz r2,current_set@l(r2)
lwz r2,TASK_FLAGS(r2)
andi. r2,r2,PF_TRACESYS
bne 50f
lis r2,sys_call_table@h
ori r2,r2,sys_call_table@l
slwi r0,r0,2
lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
mtlr r2
mr r9,r1
blrl /* Call handler */
20: stw r3,RESULT(r1) /* Save result */
cmpi 0,r3,0
bge 30f
neg r3,r3
cmpi 0,r3,ERESTARTNOHAND
bne 22f
li r3,EINTR
22: lwz r2,_CCR(r1) /* Set SO bit in CR */
oris r2,r2,0x1000
stw r2,_CCR(r1)
30: stw r3,GPR3(r1) /* Update return value */
#if 0
mr r3,r1
bl _EXTERN(trace_syscall)
#endif
b 99f
/* Traced system call support */
50: bl _EXTERN(syscall_trace)
lwz r0,GPR0(r1) /* Restore original registers */
lwz r3,GPR3(r1)
lwz r4,GPR4(r1)
lwz r5,GPR5(r1)
lwz r6,GPR6(r1)
lwz r7,GPR7(r1)
lwz r8,GPR8(r1)
lwz r9,GPR9(r1)
lis r2,sys_call_table@h
ori r2,r2,sys_call_table@l
slwi r0,r0,2
lwzx r2,r2,r0 /* Fetch system call handler [ptr] */
mtlr r2
mr r9,r1
blrl /* Call handler */
stw r3,RESULT(r1) /* Save result */
cmpi 0,r3,0
bge 60f
neg r3,r3
cmpi 0,r3,ERESTARTNOHAND
bne 52f
li r3,EINTR
52: lwz r2,_CCR(r1) /* Set SO bit in CR */
oris r2,r2,0x1000
stw r2,_CCR(r1)
60: stw r3,GPR3(r1) /* Update return value */
bl _EXTERN(syscall_trace)
99:
#if 0 /* This isn't needed here - already in RETURN_FROM_INT */
lis r2,kernel_pages_are_copyback@ha
lwz r2,kernel_pages_are_copyback@l(r2)
cmpi 0,r2,0
beq 00f
bl _EXTERN(flush_instruction_cache) /* Ensure cache coherency */
00:
#endif
RETURN_FROM_INT(0x0C00)
/*
* Handle TLB miss for instruction
*/
InstructionTLBMiss:
BUMP_UNMAPPED(__Instruction_TLB_Misses)
#ifdef DO_TLB_TRACE
lis r1,_TLB_ptr@h
ori r1,r1,_TLB_ptr@l
lis r2,0xF000
andc r1,r1,r2
lwz r1,0(r1)
andc r1,r1,r2
subi r1,r1,4
lis r2,0xBEBE
ori r2,r2,0x0100
stwu r2,4(r1)
mfspr r2,SRR0
stwu r2,4(r1)
mfspr r2,SRR1
stwu r2,4(r1)
mfspr r2,HASH1
stwu r2,4(r1)
mfspr r2,HASH2
stwu r2,4(r1)
mfspr r2,ICMP
stwu r2,4(r1)
mfspr r2,IMISS
stwu r2,4(r1)
addi r1,r1,4+(1*4)
lis r3,_TLB_ptr@h
ori r3,r3,_TLB_ptr@l
lis r2,0xF000
andc r3,r3,r2
stw r1,0(r3)
#endif
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,ICMP /* Partial item compare value */
00: li r1,8 /* 8 items / bucket */
mtctr r1
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
bdne 10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
#if 0
andi. r3,r1,0x08 /* Check guard bit - invalid access if set */
bne InstructionFetchError
#endif
andi. r3,r1,0x100 /* Check R bit (referenced) */
bne 20f /* If set, all done */
ori r1,r1,0x100 /* Set bit */
stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,IMISS /* Set to update TLB */
mtspr RPA,r1
tlbli r0
#if 0
SYNC
#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne InstructionAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
/*
* Handle TLB miss for DATA Load operation
*/
DataLoadTLBMiss:
BUMP_UNMAPPED(__DataLoad_TLB_Misses)
#ifdef DO_TLB_TRACE
lis r1,_TLB_ptr@h
ori r1,r1,_TLB_ptr@l
lis r2,0xF000
andc r1,r1,r2
lwz r1,0(r1)
andc r1,r1,r2
subi r1,r1,4
lis r2,0xBEBE
ori r2,r2,0x0200
stwu r2,4(r1)
mfspr r2,SRR0
stwu r2,4(r1)
mfspr r2,SRR1
stwu r2,4(r1)
mfspr r2,HASH1
stwu r2,4(r1)
mfspr r2,HASH2
stwu r2,4(r1)
mfspr r2,DCMP
stwu r2,4(r1)
mfspr r2,DMISS
stwu r2,4(r1)
addi r1,r1,4+(1*4)
lis r3,_TLB_ptr@h
ori r3,r3,_TLB_ptr@l
lis r2,0xF000
andc r3,r3,r2
stw r1,0(r3)
#endif
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,DCMP /* Partial item compare value */
00: li r1,8 /* 8 items / bucket */
mtctr r1
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
bdne 10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
andi. r3,r1,0x100 /* Check R bit (referenced) */
ori r1,r1,0x100 /* Set bit */
bne 20f /* If set, all done */
stw r1,4(r2) /* Update memory image */
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
/* SYNC() */
tlbld r0
#if 0
SYNC
#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne DataAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
/*
* Handle TLB miss for DATA STORE
*/
DataStoreTLBMiss:
BUMP_UNMAPPED(__DataStore_TLB_Misses)
#ifdef DO_TLB_TRACE
lis r1,_TLB_ptr@h
ori r1,r1,_TLB_ptr@l
lis r2,0xF000
andc r1,r1,r2
lwz r1,0(r1)
andc r1,r1,r2
subi r1,r1,4
lis r2,0xBEBE
ori r2,r2,0x0300
stwu r2,4(r1)
mfspr r2,SRR0
stwu r2,4(r1)
mfspr r2,SRR1
stwu r2,4(r1)
mfspr r2,HASH1
stwu r2,4(r1)
mfspr r2,HASH2
stwu r2,4(r1)
mfspr r2,DCMP
stwu r2,4(r1)
mfspr r2,DMISS
stwu r2,4(r1)
addi r1,r1,4+(1*4)
lis r3,_TLB_ptr@h
ori r3,r3,_TLB_ptr@l
lis r2,0xF000
andc r3,r3,r2
stw r1,0(r3)
#endif
mfctr r0 /* Need to save this - CTR can't be touched! */
mfspr r2,HASH1 /* Get PTE pointer */
mfspr r3,DCMP /* Partial item compare value */
00: li r1,8 /* 8 items / bucket */
mtctr r1
subi r2,r2,8 /* Preset pointer */
10: lwzu r1,8(r2) /* Get next PTE */
cmp 0,r1,r3 /* Found entry yet? */
bdne 10b /* Jump back if not, until CTR==0 */
bne 30f /* Try secondary hash if CTR==0 */
lwz r1,4(r2) /* Get second word of entry */
andi. r3,r1,0x80 /* Check C bit (changed) */
#if 0 /* Note: no validation */
beq 40f /* If not set (first time) validate access */
#else
ori r1,r1,0x180 /* Set changed, accessed */
bne 20f
stw r1,4(r2)
#endif
20: mtctr r0 /* Restore CTR */
mfspr r3,SRR1 /* Need to restore CR0 */
mtcrf 0x80,r3
mfspr r0,DMISS /* Set to update TLB */
mtspr RPA,r1
tlbld r0
#if 0
SYNC
#endif
rfi /* All done */
/* Secondary hash */
30: andi. r1,r3,0x40 /* Already doing secondary hash? */
bne DataAddressInvalid /* Yes - item not in hash table */
mfspr r2,HASH2 /* Get hash table pointer */
ori r3,r3,0x40 /* Set secondary hash */
b 00b /* Try lookup again */
/* PTE found - validate access */
40: rlwinm. r3,r1,30,0,1 /* Extract PP bits */
bge- 50f /* Jump if PP=0,1 */
andi. r3,r1,1
beq+ 70f /* Access OK */
b WriteProtectError /* Not OK - fail! */
50: mfspr r3,SRR1 /* Check privilege */
andi. r3,r3,MSR_PR
beq+ 60f /* Jump if supervisor mode */
mfspr r3,DMISS /* Get address */
mfsrin r3,r3 /* Get segment register */
andis. r3,r3,0x2000 /* If Kp==0, OK */
beq+ 70f
b WriteProtectError /* Bad access */
60: mfspr r3,DMISS /* Get address */
mfsrin r3,r3 /* Get segment register */
andis. r3,r3,0x4000 /* If Ks==0, OK */
beq+ 70f
b WriteProtectError /* Bad access */
70: ori r1,r1,0x180 /* Set changed, accessed */
stw r1,4(r2) /* Update PTE in memory */
b 20b
/*
* These routines are error paths/continuations of the exception
* handlers above. They are placed here to avoid the problems
* of only 0x100 bytes per exception handler.
*/
/* Invalid address */
InstructionAddressInvalid:
mfspr r3,SRR1
rlwinm r1,r3,9,6,6 /* Get load/store bit */
addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
b 10f
/* Fetch from guarded or no-access page */
InstructionFetchError:
mfspr r3,SRR1
rlwinm r1,r3,9,6,6 /* Get load/store bit */
addis r1,r1,0x0800 /* Set bit 4 -> protection error */
10: mtspr DSISR,r1
mtctr r0 /* Restore CTR */
andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
mtspr SRR1,r2
mfspr r1,IMISS /* Get failing address */
rlwinm. r2,r2,0,31,31 /* Check for little endian access */
beq 20f /* Jump if big endian */
xori r1,r1,3
20: mtspr DAR,r1 /* Set fault address */
mfmsr r0 /* Restore "normal" registers */
xoris r0,r0,MSR_TGPR>>16
mtcrf 0x80,r3 /* Restore CR0 */
ori r0,r0,MSR_FP /* Need to keep FP enabled */
sync /* Some chip revs have problems here... */
mtmsr r0
b InstructionAccess
/* Invalid address */
DataAddressInvalid:
mfspr r3,SRR1
rlwinm r1,r3,9,6,6 /* Get load/store bit */
addis r1,r1,0x4000 /* Set bit 1 -> PTE not found */
b 10f
/* Write to read-only space */
WriteProtectError:
mfspr r3,SRR1
rlwinm r1,r3,9,6,6 /* Get load/store bit */
addis r1,r1,0x0800 /* Set bit 4 -> protection error */
10: mtspr DSISR,r1
mtctr r0 /* Restore CTR */
andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */
mtspr SRR1,r2
mfspr r1,DMISS /* Get failing address */
rlwinm. r2,r2,0,31,31 /* Check for little endian access */
beq 20f /* Jump if big endian */
xori r1,r1,3
20: mtspr DAR,r1 /* Set fault address */
mfmsr r0 /* Restore "normal" registers */
xoris r0,r0,MSR_TGPR>>16
mtcrf 0x80,r3 /* Restore CR0 */
ori r0,r0,MSR_FP /* Need to keep FP enabled */
sync /* Some chip revs have problems here... */
mtmsr r0
b DataAccess
/*
* Flush instruction cache
* *** I'm really paranoid here!
*/
_GLOBAL(flush_instruction_cache)
mflr r5
bl _EXTERN(flush_data_cache)
mfspr r3,HID0 /* Caches are controlled by this register */
li r4,0
ori r4,r4,(HID0_ICE|HID0_ICFI)
or r3,r3,r4 /* Need to enable+invalidate to clear */
mtspr HID0,r3
andc r3,r3,r4
ori r3,r3,HID0_ICE /* Enable cache */
mtspr HID0,r3
mtlr r5
blr
/*
* Flush data cache
* *** I'm really paranoid here!
*/
_GLOBAL(flush_data_cache)
BUMP(__Cache_Flushes)
lis r3,cache_is_copyback@ha
lwz r3,cache_is_copyback@l(r3)
cmpi 0,r3,0
beq 10f
/* When DATA CACHE is copy-back */
lis r3,cache_flush_buffer@h
ori r3,r3,cache_flush_buffer@l
li r4,NUM_CACHE_LINES
mtctr r4
00: dcbz 0,r3 /* Flush cache line with minimal BUS traffic */
addi r3,r3,CACHE_LINE_SIZE /* Next line, please */
bdnz 00b
10: blr
/*
* Flush a particular page from the DATA cache
* Note: this is necessary because the instruction cache does *not*
* snoop from the data cache.
* void flush_page(void *page)
*/
_GLOBAL(flush_page)
li r4,0x0FFF
andc r3,r3,r4 /* Get page base address */
li r4,4096/CACHE_LINE_SIZE /* Number of lines in a page */
mtctr r4
00: dcbf 0,r3 /* Clear line */
icbi 0,r3
addi r3,r3,CACHE_LINE_SIZE
bdnz 00b
blr
/*
* This routine switches between two different tasks. The process
* state of one is saved on its kernel stack. Then the state
* of the other is restored from its kernel stack. The memory
* management hardware is updated to the second process's state.
* Finally, we can return to the second process, via the 'return'.
*
* Note: there are two ways to get to the "going out" portion
* of this code; either by coming in via the entry (_switch)
* or via "fork" which must set up an environment equivalent
* to the "_switch" path. If you change this (or in particular, the
* SAVE_REGS macro), you'll have to change the fork code also.
*
* The code which creates the new task context is in 'copy_thread'
* in arch/ppc/kernel/process.c
*/
_GLOBAL(_switch)
mtspr SPR0,r1 /* SAVE_REGS prologue */
mtspr SPR1,r2
mflr r2 /* Return to switch caller */
mtspr SPR2,r2
mfmsr r2
mtspr SPR3,r2
SAVE_REGS(0x0FF0)
SYNC()
stw r1,KSP(r3) /* Set old stack pointer */
BUMP(__Context_Switches)
lwz r1,KSP(r4) /* Load new stack pointer */
CHECK_STACK()
lwz r0,MMU_SEG0(r4)
mtsr SR0,r0
lwz r0,MMU_SEG1(r4)
mtsr SR1,r0
lwz r0,MMU_SEG2(r4)
mtsr SR2,r0
lwz r0,MMU_SEG3(r4)
mtsr SR3,r0
lwz r0,MMU_SEG4(r4)
mtsr SR4,r0
lwz r0,MMU_SEG5(r4)
mtsr SR5,r0
lwz r0,MMU_SEG6(r4)
mtsr SR6,r0
lwz r0,MMU_SEG7(r4)
mtsr SR7,r0
lwz r0,MMU_SEG8(r4)
mtsr SR8,r0
lwz r0,MMU_SEG9(r4)
mtsr SR9,r0
lwz r0,MMU_SEG10(r4)
mtsr SR10,r0
lwz r0,MMU_SEG11(r4)
mtsr SR11,r0
lwz r0,MMU_SEG12(r4)
mtsr SR12,r0
lwz r0,MMU_SEG13(r4)
mtsr SR13,r0
lwz r0,MMU_SEG14(r4)
mtsr SR14,r0
lwz r0,MMU_SEG15(r4)
mtsr SR15,r0
tlbia /* Invalidate entire TLB */
BUMP(__TLBIAs)
bl _EXTERN(flush_instruction_cache)
#ifdef TLB_STATS
/* TEMP */
lis r2,DataLoadTLB_trace_ptr@h
ori r2,r2,DataLoadTLB_trace_ptr@l
lis r3,0x9000
lwz r4,0(r2)
or r4,r4,r3
li r0,0
stw r0,0(r4)
stw r0,4(r4)
stw r0,8(r4)
stw r0,12(r4)
addi r4,r4,4
cmpl 0,r4,r2
blt 00f
lis r4,DataLoadTLB_trace_buf@h
ori r4,r4,DataLoadTLB_trace_buf@l
00: stw r4,0(r2)
/* TEMP */
#endif
#if 0
lwz r2,_NIP(r1) /* Force TLB/MMU hit */
lwz r2,0(r2)
#endif
RETURN_FROM_INT(0xF000)
/*
* This routine is just here to keep GCC happy - sigh...
*/
_GLOBAL(__main)
blr
#ifdef DO_TRAP_TRACE
check_trace:
sync /* Force all writes out */
lwz r2,-8(r1)
andi. r2,r2,MSR_PR
bne 99f
lwz r2,-32(r1)
lwz r3,-16(r1)
cmp 0,r2,r3
bne 99f
andi. r2,r2,0x7FFF
cmpi 0,r2,0x0C00
bge 99f
lwz r2,-32+4(r1)
lwz r3,-16+4(r1)
cmp 0,r2,r3
bne 99f
lwz r2,-32+8(r1)
lwz r3,-16+8(r1)
cmp 0,r2,r3
bne 99f
lwz r2,-32(r1)
lwz r3,-16(r1)
cmp 0,r2,r3
bne 99f
andi. r2,r2,0x7FFF
cmpi 0,r2,0x0600
beq 00f
lwz r2,-32+12(r1)
lwz r3,-16+12(r1)
cmp 0,r2,r3
bne 99f
00: li r2,0x7653
stw r2,0(r1)
b 00b
99: blr
#endif
.data
.globl sdata
sdata:
.space 2*4096
sys_stack:
.space 2*4096
CPU1_stack:
.globl empty_zero_page
empty_zero_page:
.space 4096
.globl swapper_pg_dir
swapper_pg_dir:
.space 4096
/*
* This space gets a copy of optional info passed to us by the bootstrap
* Used to pass parameters into the kernel like root=/dev/sda1, etc.
*/
.globl cmd_line
cmd_line:
.space 512
#ifdef STATS
/*
* Miscellaneous statistics - gathered just for performance info
*/
.globl _INTR_stats
_INTR_stats:
__Instruction_TLB_Misses:
.long 0,0 /* Instruction TLB misses */
__DataLoad_TLB_Misses:
.long 0,0 /* Data [load] TLB misses */
__DataStore_TLB_Misses:
.long 0,0 /* Data [store] TLB misses */
__Instruction_Page_Faults:
.long 0,0 /* Instruction page faults */
__Data_Page_Faults:
.long 0,0 /* Data page faults */
__Cache_Flushes:
.long 0,0 /* Explicit cache flushes */
__Context_Switches:
.long 0,0 /* Context switches */
__Hardware_Interrupts:
.long 0,0 /* I/O interrupts (disk, timer, etc) */
.globl __TLBIAs
__TLBIAs:
.long 0,0 /* TLB cache forceably flushed */
.globl __TLBIEs
__TLBIEs:
.long 0,0 /* Specific TLB entry flushed */
#endif
/*
* This location is used to break any outstanding "lock"s when
* changing contexts.
*/
_break_lwarx: .long 0
/*
* Various trace buffers
*/
#ifdef DO_TRAP_TRACE
.data
_TRAP_TRACE: .space 32*1024
_TRAP_ptr: .long _TRAP_TRACE
.text
#endif
#ifdef DO_TLB_TRACE
.data
_TLB_TRACE: .space 128*1024
_TLB_ptr: .long _TLB_TRACE
.text
#endif
#ifdef DO_RFI_TRACE
.data
_RFI_DATA: .space 128*1024
_RFI_ptr: .long _RFI_DATA
.text
#endif