1 #include <asm/processor.h>
4 #include <asm/pgtable.h>
5 #include <asm/cputable.h>
7 #include <asm/thread_info.h>
8 #include <asm/ppc_asm.h>
9 #include <asm/asm-offsets.h>
12 * Code execution starts here.
14 * The code is loaded at the correct address (0) by the boot loader.
15 * The following registers contain valid information:
18 * r4 - IPL extended info block
22 .stabs "arch/ppc/kernel/",N_SO,0,0,0f
23 .stabs "head.S",N_SO,0,0,0f
31 * Save parameters we are passed
35 li r24,0 /* CPU number */
39 * Establish a default MSR
45 #if 0 /* No need its there anyway. */
47 * Setup a stack right in front of the BIOS information passed
52 #if 1 /* Initialize serial port for debugging */
57 * early_init() does the early machine identification and does
58 * the necessary low-level setup and clears the BSS
59 * -- Cort <cort@fsmlabs.com>
64 /* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains
65 * the physical address we are running at, returned by early_init()
71 /* Setup some kind of mapping
75 /* Start into the kernel address space
78 ori r0,r0,MSR_DR|MSR_IR
81 ori r0,r0,start_here@l
88 stw r10,_SPRG0@l(0); \
89 stw r11,_SPRG1@l(0); \
92 mtspr SPRN_SRR0,r11; \
94 andil. r11,r11,0xffff; \
95 mtspr SPRN_SRR1,r11; \
100 #define EXCEPTION(n, label, hdlr, xfer) \
104 addi r3,r1,STACK_FRAME_OVERHEAD; \
108 #define EXCEPTION_PROLOG \
109 stw r10,_SPRG0@l(0); \
110 stw r11,_SPRG1@l(0); \
112 EXCEPTION_PROLOG_1; \
115 #define EXCEPTION_PROLOG_1 \
116 mfspr r11,SPRN_SRR1; /* check wether user or kernel */ \
117 andi. r11,r11,MSR_PR; \
118 tophys(r11,r1); /* use tophys(r1) if kernel */ \
120 lwz r11,_SPRG3@l(0); \
121 lwz r11,THREAD_INFO-THREAD(r11); \
122 addi r11,r11,THREAD_SIZE; \
124 1: subi r11,r11,INT_FRAME_SIZE; /* alloc exc- frame */
126 #define EXCEPTION_PROLOG_2 \
129 stw r12,GPR12(r11); \
131 lwz r10,_SPRG0@l(0); \
132 stw r10,GPR10(r11); \
133 lwz r12,_SPRG1@l(0); \
134 stw r12,GPR11(r11); \
136 stw r10,_LINK(r11); \
137 mfspr r12,SPRN_SRR0; \
138 mfspr r9,SPRN_SRR1; \
141 tovirt(r1,r11); /* set new kernel sp */ \
142 li r10,MSR_KERNEL & ~(MSR_IR|MSR_DR); /* can take exceptions */ \
145 SAVE_4GPRS(3, r11); \
148 #define EXC_XFER_TEMPLATE(n, hdlr, trap, copyee, tfer, ret) \
158 #define COPY_EE(d, s) rlwimi d,s,0,16,16
161 #define EXC_XFER_STD(n, hdlr) \
162 EXC_XFER_TEMPLATE(n, hdlr, n, NOCOPY, transfer_to_handler_full, \
163 ret_from_except_full)
165 #define EXC_XFER_LITE(n, hdlr) \
166 EXC_XFER_TEMPLATE(n, hdlr, n+1, NOCOPY, transfer_to_handler, \
169 #define EXC_XFER_EE(n, hdlr) \
170 EXC_XFER_TEMPLATE(n, hdlr, n, COPY_EE, transfer_to_handler_full, \
171 ret_from_except_full)
173 #define EXC_XFER_EE_LITE(n, hdlr) \
174 EXC_XFER_TEMPLATE(n, hdlr, n+1, COPY_EE, transfer_to_handler, \
179 #if 1 /* For debugging purpose we install our own trap handlers */
181 .macro panic errtxt, ledcod
182 stm 0,saved_regs_ex-_start(0)
183 # last segment, wraps to zero on first loop run
185 # offset to reach the next segment
187 # start saving 4 bytes later
188 li 5,saved_regs_ex-_start+32*4-4
189 # stop when we would next store there
190 li 6,saved_regs_ex-_start+32*4+16*4
197 li 1,_stack_ex-_start+4096-16
204 li 3,\errtxt - _start
247 7: EXCEPTION_PROLOG_2
248 addi r3,r1,STACK_FRAME_OVERHEAD
249 EXC_XFER_STD(0x200, machine_check_exception)
253 /* Data access exception. */
258 andis. r0,r10,0xa470 /* weird error? */
259 bne 1f /* if not, try to put a PTE */
260 mfspr r4,SPRN_DAR /* into the hash table */
261 rlwinm r3,r10,32-20,26,26 /* DSISR_STORE -> _PAGE_RW */
263 1: stw r10,_DSISR(r11)
266 EXC_XFER_EE_LITE(0x300, handle_page_fault)
272 EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
277 EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
280 /* Floating-point unavailable */
284 bne load_up_fpu /* if from user, just load it up */
285 addi r3,r1,STACK_FRAME_OVERHEAD
286 EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
306 EXC_XFER_EE_LITE(0x1000, DoSyscall)
313 saved_regs_ex: .space 32*4
316 err1: .asciz "\r\nPANIC ERROR SYSTEM RESET"
317 err2: .asciz "\r\nPANIC ERROR MACHINE CHECK"
318 err3: .asciz "\r\nPANIC ERROR DATA STORAGE"
319 err4: .asciz "\r\nPANIC ERROR INSTRUCTION STORAGE"
320 err5: .asciz "\r\nPANIC ERROR EXTERNAL INTERRUPT"
321 err6: .asciz "\r\nPANIC ERROR ALIGNMENT INTERRUPT"
322 err7: .asciz "\r\nPANIC ERROR PROGRAM"
323 err8: .asciz "\r\nPANIC ERROR FPU UNAVAIL"
324 err9: .asciz "\r\nPANIC ERROR 9"
325 err10: .asciz "\r\nPANIC ERROR 10"
326 err11: .asciz "\r\nPANIC ERROR 11"
327 err12: .asciz "\r\nPANIC ERROR 12"
328 err13: .asciz "\r\nPANIC ERROR 13"
329 err14: .asciz "\r\nPANIC ERROR 14"
330 err15: .asciz "\r\nPANIC ERROR 15"
331 err16: .asciz "\r\nPANIC SYSTEM CALL 0"
335 _r0: .asciz "\r\nr0 ";
343 _r8: .asciz "\r\nr8 ";
345 _r10: .asciz " r10 ";
346 _r11: .asciz " r11 ";
347 _r12: .asciz " r12 ";
348 _r13: .asciz " r13 ";
349 _r14: .asciz " r14 ";
350 _r15: .asciz " r15 ";
351 _r16: .asciz "\r\nr16 ";
352 _r17: .asciz " r17 ";
353 _r18: .asciz " r18 ";
354 _r19: .asciz " r19 ";
355 _r20: .asciz " r20 ";
356 _r21: .asciz " r21 ";
357 _r22: .asciz " r22 ";
358 _r23: .asciz " r23 ";
359 _r24: .asciz "\r\nr24 ";
360 _r25: .asciz " r25 ";
361 _r26: .asciz " r26 ";
362 _r27: .asciz " r27 ";
363 _r28: .asciz " r28 ";
364 _r29: .asciz " r29 ";
365 _r30: .asciz " r30 ";
366 _r31: .asciz " r31 ";
367 _sr0: .asciz "\r\nsr0 ";
368 _sr1: .asciz " sr1 ";
369 _sr2: .asciz " sr2 ";
370 _sr3: .asciz " sr3 ";
371 _sr4: .asciz " sr4 ";
372 _sr5: .asciz " sr5 ";
373 _sr6: .asciz " sr6 ";
374 _sr7: .asciz " sr7 ";
375 _sr8: .asciz "\r\nsr8 ";
376 _sr9: .asciz " sr9 ";
377 _sr10: .asciz " sr10 ";
378 _sr11: .asciz " sr11 ";
379 _sr12: .asciz " sr12 ";
380 _sr13: .asciz " sr13 ";
381 _sr14: .asciz " sr14 ";
382 _sr15: .asciz " sr15 ";
438 li r25,_regs - _start - 4
440 li 26,saved_regs_ex - _start - 4
458 li 26,saved_regs_ex - _start - 4
459 lwz 25,8(26) # saved 1
471 bl rs6000_serial_putc
475 bl rs6000_serial_putc
479 bl rs6000_serial_putc
483 bl rs6000_serial_putc
487 bl rs6000_serial_putc
491 bl rs6000_serial_putc
495 bl rs6000_serial_putc
499 bl rs6000_serial_putc
514 EXCEPTION(0x100, Reset, unknown_exception, EXC_XFER_STD)
522 7: EXCEPTION_PROLOG_2
523 addi r3,r1,STACK_FRAME_OVERHEAD
524 EXC_XFER_STD(0x200, machine_check_exception)
526 /* Data access exception. */
531 andis. r0,r10,0xa470 /* weird error? */
532 bne 1f /* if not, try to put a PTE */
533 mfspr r4,SPRN_DAR /* into the hash table */
534 rlwinm r3,r10,32-15,21,21 /* DSISR_STORE -> _PAGE_RW */
536 1: stw r10,_DSISR(r11)
539 EXC_XFER_EE_LITE(0x300, handle_page_fault)
541 /* Instruction access exception. */
545 andis. r0,r9,0x4000 /* no pte found? */
546 beq 1f /* if so, try to put a PTE */
547 li r3,0 /* into the hash table */
548 mr r4,r12 /* SRR0 is fault address */
552 EXC_XFER_EE_LITE(0x400, handle_page_fault)
554 /* External interrupt */
555 EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE)
557 /* Alignment exception */
565 addi r3,r1,STACK_FRAME_OVERHEAD
566 EXC_XFER_EE(0x600, alignment_exception)
568 /* Program check exception */
569 EXCEPTION(0x700, ProgramCheck, program_check_exception, EXC_XFER_STD)
571 /* Floating-point unavailable */
575 bne load_up_fpu /* if from user, just load it up */
576 addi r3,r1,STACK_FRAME_OVERHEAD
577 EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception)
580 EXCEPTION(0x900, Decrementer, timer_interrupt, EXC_XFER_LITE)
582 EXCEPTION(0xa00, Trap_0a, unknown_exception, EXC_XFER_EE)
583 EXCEPTION(0xb00, Trap_0b, unknown_exception, EXC_XFER_EE)
589 EXC_XFER_EE_LITE(0xc00, DoSyscall)
592 EXCEPTION(0xe00, Trap_0e, unknown_exception, EXC_XFER_EE)
599 addi r3,r1,STACK_FRAME_OVERHEAD
600 EXC_XFER_EE(0xf00, unknown_exception)
602 #endif // Debugging traps
614 * Load stuff into the MMU. Intended to be called with
619 dcs /* Force all PTE updates to finish */
621 bl flush_tlbs /* (was: tlbia) Clear all TLB entries */
622 dcs /* wait for tlbia/tlbie to finish */
623 TLBSYNC /* ... on all CPUs */
624 /* Load the SDR1 register (hash table base & size) */
629 li r0,16 /* load up segment register values */
630 mtctr r0 /* for context 0 */
631 lis r3,0x2000 /* Ku = 1, VSID = 0 */
634 addi r3,r3,0x111 /* increment VSID */
635 addis r4,r4,0x1000 /* address of next segment */
640 /* Load the BAT registers with the values set up by MMU_init.
641 MMU_init takes care of whether we're on a 601 or not. */
657 /* This is where the main kernel code starts.
662 ori r2,r2,init_task@l
664 /* ptr to phys current thread */
666 addi r4,r4,THREAD /* init task's THREAD */
672 lis r1,init_thread_union@ha
673 addi r1,r1,init_thread_union@l
675 stwu r0,THREAD_SIZE-STACK_FRAME_OVERHEAD(r1)
679 ori r3,r3,hello_world@l
683 * Do early bootinfo parsing, platform-specific initialization,
684 * and set up the MMU.
696 * Go back to running unmapped so we can load up new values
697 * for SDR1 (hash table pointer) and the segment registers
698 * and change to using our exception vectors.
703 li r3,MSR_KERNEL & ~(MSR_IR|MSR_DR)
709 /* Load up the kernel context */
718 * Setup some segment register values which stick
726 // We can address the first MCA bus by
727 // the following segment values:
736 // IOCC of first MCA bus
744 * Enable all interrupts in the local IOCC
757 /* Now turn on the MMU for real! */
760 lis r3,start_kernel@h
761 ori r3,r3,start_kernel@l
768 * Set up the segment registers for a new context.
771 mulli r3,r3,897 /* multiply context by skew factor */
772 rlwinm r3,r3,4,8,27 /* VSID = (context & 0xfffff) << 4 */
773 addis r3,r3,0x6000 /* Set Ks, Ku bits */
774 li r0,NUM_USER_SEGMENTS
777 #ifdef CONFIG_BDI_SWITCH
778 /* Context switch the PTE pointer for the Abatron BDI2000.
779 * The PGDIR is passed as second argument.
789 addi r3,r3,0x111 /* next VSID */
790 rlwinm r3,r3,0,8,3 /* clear out any overflow from VSID field */
791 addis r4,r4,0x1000 /* address of next segment */
799 1: addic. r10, r10, -0x1000
806 addi r4, r3, __after_mmu_off - _start
808 andi. r0,r3,MSR_DR|MSR_IR /* MMU enabled? */
828 lil 28,52 # 9600 baud
844 .macro enter firstreg,alloc=0
845 .set SAVED_REGS_START,\firstreg
846 .set SAVED_REGS_OFS,-4*(32-SAVED_REGS_START)
847 .set SAVED_SP,SAVED_REGS_OFS-16-\alloc
850 .set RESTORE_LR,SAVED_LR-SAVED_SP
851 mflr 0 # Get return address
852 stm SAVED_REGS_START,SAVED_REGS_OFS(1)
861 lm SAVED_REGS_START,SAVED_REGS_OFS(1)
865 .global rs6000_serial_putc
885 .global rs6000_display_long
895 rlinm 28,28,4,0xffffffff # rotate 4
896 rlinm 29,28,0,0xf # select lower 4
897 ai. 3,29,-10 # convert to letter
900 ai 3,29,0x30 # convert to number
902 bl rs6000_serial_putc
909 rlinm 4,4,4,0xffffffff # rotate 4
910 rlinm 5,4,0,0xf # select lower 4
911 ai. 3,5,-10 # convert to letter
914 ai 3,5,0x30 # convert to number
916 bl rs6000_serial_putc
934 bl rs6000_serial_putc
941 hello_world: .asciz "Hello world!\r\n"
966 * Setup the HAT and PFT entries for segment 0 until the HAT is fully
967 * populated. A 32kB HAT has 8192 entries which map 32 MB. This
968 * should be sufficient to hold the kernel.
973 lil r3,-0x8000 # - Size of HAT, 32kB
974 add r29,r3,r31 # Position of HAT
975 rlinm r29,r29,0,0,16 # Align to 32kB boundary
976 addis r3,r29,-0x10 # - 1 MB
977 rlinm r28,r3,0,0,11 # Align to 1MB border
982 ori r5,r5,0x2000 # -> 8192 entries
984 lis r5,0 # Page index
985 addi r6,r29,-4 # HAT address
986 addi r7,r28,-4 # PFT address
987 lil r8,0x10 # First word of PFT entry
992 ori r5,r5,0x1FFF # -> 8192 entries
994 lis r5,0 # Page index
995 addi r6,r29,-4 # HAT address
996 addi r7,r28,-4 # PFT address
997 lil r8,0x10 # First word of PFT entry
1006 ai r5,r5,1 # next PFT entry
1009 stu r5,4(r6) # Page index is HAT entry
1010 # First word of PFT entry is zero but the valid bit
1012 # Next entry has only bit 0 set for invalid
1014 # Other words of PFT entry are zero
1018 ai r5,r5,1 # next PFT entry
1021 # Load SDRx register
1024 mtspr SPRN_SDR1,r3 # HAT mask is 0 anyway
1032 * We put a few things here that have to be page-aligned.
1033 * This stuff goes at the beginning of the data segment,
1034 * which is page-aligned.
1039 .globl empty_zero_page
1043 .globl swapper_pg_dir
1048 * This space gets a copy of optional info passed to us by the bootstrap
1049 * Used to pass parameters into the kernel like root=/dev/sda1, etc.