📄 head.s
字号:
/* * arch/ppc/kernel/head.S * * $Id: head.S,v 1.154 1999/10/12 00:33:31 cort Exp $ * * PowerPC version * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) * * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> * Adapted for Power Macintosh by Paul Mackerras. * Low-level exception handlers and MMU support * rewritten by Paul Mackerras. * Copyright (C) 1996 Paul Mackerras. * MPC8xx modifications Copyright (C) 1997 Dan Malek (dmalek@jlc.net). * Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk). * * This file contains the low-level support and setup for the * PowerPC platform, including trap and interrupt dispatch. * (The PPC 8xx embedded CPUs use head_8xx.S instead.) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */#include "ppc_asm.h"#include <asm/processor.h>#include <asm/page.h>#include <linux/config.h>#include <asm/mmu.h>#include "mol.h"#ifdef CONFIG_APUS#include <asm/amigappc.h>#endif#ifndef CONFIG_PPC64BRIDGECACHELINE_BYTES = 32LG_CACHELINE_BYTES = 5CACHELINE_MASK = 0x1fCACHELINE_WORDS = 8#elseCACHELINE_BYTES = 128LG_CACHELINE_BYTES = 7CACHELINE_MASK = 0x7fCACHELINE_WORDS = 32#endif /* CONFIG_PPC64BRIDGE */#ifdef CONFIG_PPC64BRIDGE#define LOAD_BAT(n, reg, RA, RB) \ ld RA,(n*32)+0(reg); \ ld RB,(n*32)+8(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ ld RA,(n*32)+16(reg); \ ld RB,(n*32)+24(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \ #else /* CONFIG_PPC64BRIDGE */ /* 601 only have IBAT; cr0.eq is set on 601 when using this macro */#define LOAD_BAT(n, reg, RA, RB) \ /* see the comment for clear_bats() -- Cort */ \ li RA,0; \ mtspr IBAT##n##U,RA; \ mtspr DBAT##n##U,RA; \ lwz RA,(n*16)+0(reg); \ lwz RB,(n*16)+4(reg); \ mtspr IBAT##n##U,RA; \ mtspr IBAT##n##L,RB; \ beq 1f; \ lwz RA,(n*16)+8(reg); \ lwz RB,(n*16)+12(reg); \ mtspr DBAT##n##U,RA; \ mtspr DBAT##n##L,RB; \1: #endif /* CONFIG_PPC64BRIDGE */ .text .globl _stext_stext:/* * _start is defined this way because the XCOFF loader in the OpenFirmware * on the powermac expects the entry point to be a procedure descriptor. */ .text .globl _start_start: /* * These are here for legacy reasons, the kernel used to * need to look like a coff function entry for the pmac * but we're always started by some kind of bootloader now. * -- Cort */ nop nop nop/* PMAC * Enter here with the kernel text, data and bss loaded starting at * 0, running with virtual == physical mapping. * r5 points to the prom entry point (the client interface handler * address). Address translation is turned on, with the prom * managing the hash table. Interrupts are disabled. The stack * pointer (r1) points to just below the end of the half-meg region * from 0x380000 - 0x400000, which is mapped in already. * * If we are booted from MacOS via BootX, we enter with the kernel * image loaded somewhere, and the following values in registers: * r3: 'BooX' (0x426f6f58) * r4: virtual address of boot_infos_t * r5: 0 * * APUS * r3: 'APUS' * r4: physical address of memory base * Linux/m68k style BootInfo structure at &_end. * * PREP * This is jumped to on prep systems right after the kernel is relocated * to its proper place in memory by the boot loader. The expected layout * of the regs is: * r3: ptr to residual data * r4: initrd_start or if no initrd then 0 * r5: initrd_end - unused if r4 is 0 * r6: Start of command line string * r7: End of command line string * * This just gets a minimal mmu environment setup so we can call * start_here() to do the real work. * -- Cort */ .globl __start__start:/* * We have to do any OF calls before we map ourselves to KERNELBASE, * because OF may have I/O devices mapped into that area * (particularly on CHRP). */ mr r31,r3 /* save parameters */ mr r30,r4 mr r29,r5 mr r28,r6 mr r27,r7 li r24,0 /* cpu # */ bl prom_init#ifdef CONFIG_APUS/* On APUS the __va/__pa constants need to be set to the correct * values before continuing. */ mr r4,r30 bl fix_mem_constants#endif /* CONFIG_APUS */#ifndef CONFIG_GEMINI/* Switch MMU off, clear BATs and flush TLB. At this point, r3 contains * the physical address we are running at, returned by prom_init() */ bl mmu_off__after_mmu_off: bl clear_bats bl flush_tlbs#endif#ifndef CONFIG_POWER4 /* POWER4 doesn't have BATs */ bl initial_bats#if !defined(CONFIG_APUS) && defined(CONFIG_BOOTX_TEXT) bl setup_disp_bat#endif#else /* CONFIG_POWER4 *//* * Load up the SDR1 and segment register values now * since we don't have the BATs. */ bl reloc_offset addis r4,r3,_SDR1@ha /* get the value from _SDR1 */ lwz r4,_SDR1@l(r4) /* assume hash table below 4GB */ mtspr SDR1,r4 slbia lis r5,0x2000 /* set pseudo-segment reg 12 */ ori r5,r5,12 mtsr 12,r5#endif /* CONFIG_POWER4 */#ifndef CONFIG_APUS/* * We need to run with _start at physical address 0. * On CHRP, we are loaded at 0x10000 since OF on CHRP uses * the exception vectors at 0 (and therefore this copy * overwrites OF's exception vectors with our own). * If the MMU is already turned on, we copy stuff to KERNELBASE, * otherwise we copy it to 0. */ bl reloc_offset mr r26,r3 addis r4,r3,KERNELBASE@h /* current address of _start */ cmpwi 0,r4,0 /* are we already running at 0? */ bne relocate_kernel#endif /* CONFIG_APUS *//* * we now have the 1st 16M of ram mapped with the bats. * prep needs the mmu to be turned on here, but pmac already has it on. * this shouldn't bother the pmac since it just gets turned on again * as we jump to our code at KERNELBASE. -- Cort * Actually no, pmac doesn't have it on any more. BootX enters with MMU * off, and in other cases, we now turn it off before changing BATs above. */turn_on_mmu: mfmsr r0 ori r0,r0,MSR_DR|MSR_IR mtspr SRR1,r0 lis r0,start_here@h ori r0,r0,start_here@l mtspr SRR0,r0 SYNC RFI /* enables MMU */#ifdef CONFIG_SMP .globl __secondary_hold__secondary_hold: /* tell the master we're here */ stw r3,4(0)100: lwz r4,0(0) /* wait until we're told to start */ cmpw 0,r4,r3 bne 100b /* our cpu # was at addr 0 - go */ mr r24,r3 /* cpu # */ b __secondary_start#endif/* * Exception entry code. This code runs with address translation * turned off, i.e. using physical addresses. * We assume sprg3 has the physical address of the current * task's thread_struct. */#define EXCEPTION_PROLOG \ mtspr SPRG0,r20; \ mtspr SPRG1,r21; \ mfcr r20; \ mfspr r21,SPRG2; /* exception stack to use from */ \ cmpwi 0,r21,0; /* user mode or RTAS */ \ bne 1f; \ tophys(r21,r1); /* use tophys(kernel sp) otherwise */ \ subi r21,r21,INT_FRAME_SIZE; /* alloc exc. frame */\1: CLR_TOP32(r21); \ stw r20,_CCR(r21); /* save registers */ \ stw r22,GPR22(r21); \ stw r23,GPR23(r21); \ mfspr r20,SPRG0; \ stw r20,GPR20(r21); \ mfspr r22,SPRG1; \ stw r22,GPR21(r21); \ mflr r20; \ stw r20,_LINK(r21); \ mfctr r22; \ stw r22,_CTR(r21); \ mfspr r20,XER; \ stw r20,_XER(r21); \ mfspr r22,SRR0; \ mfspr r23,SRR1; \ stw r0,GPR0(r21); \ stw r1,GPR1(r21); \ stw r2,GPR2(r21); \ stw r1,0(r21); \ tovirt(r1,r21); /* set new kernel sp */ \ SAVE_4GPRS(3, r21); \ SAVE_GPR(7, r21);/* * Note: code which follows this uses cr0.eq (set if from kernel), * r21, r22 (SRR0), and r23 (SRR1). *//* * Exception vectors. */#define STD_EXCEPTION(n, label, hdlr) \ . = n; \label: \ EXCEPTION_PROLOG; \ addi r3,r1,STACK_FRAME_OVERHEAD; \ li r20,MSR_KERNEL; \ bl transfer_to_handler; \ .long hdlr; \ .long ret_from_except#define STD_MOL_EXCEPTION(n, label, hdlr, hook) \ . = n; \label: \ EXCEPTION_PROLOG; \ MOL_HOOK(hook); \ addi r3,r1,STACK_FRAME_OVERHEAD; \ li r20,MSR_KERNEL; \ bl transfer_to_handler; \ .long hdlr; \ .long ret_from_except/* System reset */#ifdef CONFIG_SMP /* MVME/MTX and gemini start the secondary here */#ifdef CONFIG_GEMINI . = 0x100 b __secondary_start_gemini#else /* CONFIG_GEMINI */ STD_EXCEPTION(0x100, Reset, __secondary_start_psurge)#endif /* CONFIG_GEMINI */#else STD_EXCEPTION(0x100, Reset, UnknownException)#endif/* Machine check */ STD_EXCEPTION(0x200, MachineCheck, MachineCheckException)/* Data access exception. */ . = 0x300#ifdef CONFIG_PPC64BRIDGE b DataAccessDataAccessCont:#elseDataAccess: EXCEPTION_PROLOG#endif /* CONFIG_PPC64BRIDGE */ MOL_HOOK(0) mfspr r20,DSISR andis. r0,r20,0xa470 /* weird error? */ bne 1f /* if not, try to put a PTE */ mfspr r3,DAR /* into the hash table */ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ rlwimi r4,r20,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ bl hash_page1: stw r20,_DSISR(r21) mr r5,r20 mfspr r4,DAR stw r4,_DAR(r21) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault .long ret_from_except#ifdef CONFIG_PPC64BRIDGE/* SLB fault on data access. */ . = 0x380 b DataSegmentDataSegmentCont: mfspr r4,DAR stw r4,_DAR(r21) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long UnknownException .long ret_from_except#endif /* CONFIG_PPC64BRIDGE *//* Instruction access exception. */ . = 0x400#ifdef CONFIG_PPC64BRIDGE b InstructionAccessInstructionAccessCont:#elseInstructionAccess: EXCEPTION_PROLOG#endif /* CONFIG_PPC64BRIDGE */ MOL_HOOK(1) andis. r0,r23,0x4000 /* no pte found? */ beq 1f /* if so, try to put a PTE */ mr r3,r22 /* into the hash table */ rlwinm r4,r23,32-13,30,30 /* MSR_PR -> _PAGE_USER */ mr r20,r23 /* SRR1 has reason bits */ bl hash_page1: addi r3,r1,STACK_FRAME_OVERHEAD mr r4,r22 mr r5,r23 li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long do_page_fault .long ret_from_except#ifdef CONFIG_PPC64BRIDGE/* SLB fault on instruction access. */ . = 0x480 b InstructionSegmentInstructionSegmentCont: addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long UnknownException .long ret_from_except#endif /* CONFIG_PPC64BRIDGE *//* External interrupt */ . = 0x500;HardwareInterrupt: EXCEPTION_PROLOG; addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL#ifndef CONFIG_APUS li r4,0 bl transfer_to_handler .globl do_IRQ_interceptdo_IRQ_intercept: .long do_IRQ; .long ret_from_intercept#else bl apus_interrupt_entry#endif /* CONFIG_APUS *//* Alignment exception */ . = 0x600Alignment: EXCEPTION_PROLOG mfspr r4,DAR stw r4,_DAR(r21) mfspr r5,DSISR stw r5,_DSISR(r21) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long AlignmentException .long ret_from_except/* Program check exception */ . = 0x700ProgramCheck: EXCEPTION_PROLOG MOL_HOOK(2) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long ProgramCheckException .long ret_from_except/* Floating-point unavailable */ . = 0x800FPUnavailable: EXCEPTION_PROLOG MOL_HOOK_RESTORE(3) bne load_up_fpu /* if from user, just load it up */ li r20,MSR_KERNEL bl transfer_to_handler /* if from kernel, take a trap */ .long KernelFP .long ret_from_except . = 0x900Decrementer: EXCEPTION_PROLOG MOL_HOOK(4) addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler .globl timer_interrupt_intercepttimer_interrupt_intercept: .long timer_interrupt .long ret_from_intercept STD_EXCEPTION(0xa00, Trap_0a, UnknownException) STD_EXCEPTION(0xb00, Trap_0b, UnknownException)/* System call */ . = 0xc00SystemCall: EXCEPTION_PROLOG stw r3,ORIG_GPR3(r21) li r20,MSR_KERNEL rlwimi r20,r23,0,16,16 /* copy EE bit from saved MSR */ bl transfer_to_handler .long DoSyscall .long ret_from_except/* Single step - not used on 601 */ STD_MOL_EXCEPTION(0xd00, SingleStep, SingleStepException, 5) STD_EXCEPTION(0xe00, Trap_0e, UnknownException)/* * The Altivec unavailable trap is at 0x0f20. Foo. * We effectively remap it to 0x3000. */ . = 0xf00 b Trap_0ftrap_0f_cont: addi r3,r1,STACK_FRAME_OVERHEAD li r20,MSR_KERNEL bl transfer_to_handler .long UnknownException .long ret_from_except . = 0xf20#ifdef CONFIG_ALTIVEC b AltiVecUnavailable#endifTrap_0f: EXCEPTION_PROLOG b trap_0f_cont /* * Handle TLB miss for instruction on 603/603e. * Note: we get an alternate set of r0 - r3 to use automatically. */ . = 0x1000InstructionTLBMiss: MOL_HOOK_TLBMISS( 14 )/* * r0: stored ctr * r1: linux style pte ( later becomes ppc hardware pte ) * r2: ptr to linux-style pte * r3: scratch */ mfctr r0 /* Get PTE (linux-style) and check access */ mfspr r3,IMISS lis r1,KERNELBASE@h /* check if kernel address */ cmplw 0,r3,r1 mfspr r2,SPRG3 lwz r2,PGDIR(r2) blt+ 112f lis r2,swapper_pg_dir@ha /* if kernel address, use */ addi r2,r2,swapper_pg_dir@l /* kernel page table */112: tophys(r2,r2) rlwimi r2,r3,12,20,29 /* insert top 10 bits of address */ lwz r2,0(r2) /* get pmd entry */ rlwinm. r2,r2,0,0,19 /* extract address of pte page */ beq- InstructionAddressInvalid /* return if no mapping */ tophys(r2,r2) rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ lwz r1,0(r2) /* get linux-style pte */ /* setup access flags in r3 */ mfmsr r3 rlwinm r3,r3,32-13,30,30 /* MSR_PR -> _PAGE_USER */ ori r3,r3,1 /* set _PAGE_PRESENT bit in access */ andc. r3,r3,r1 /* check access & ~permission */ bne- InstructionAddressInvalid /* return if access not permitted */ ori r1,r1,0x100 /* set _PAGE_ACCESSED in pte */ stw r1,0(r2) /* update PTE (accessed bit) */ /* Convert linux-style PTE to low word of PPC-style PTE */ /* this computation could be done better -- Cort */ rlwinm r3,r1,32-9,31,31 /* _PAGE_HWWRITE -> PP lsb */ rlwimi r1,r1,32-1,31,31 /* _PAGE_USER -> PP (both bits now) */ ori r3,r3,0xe04 /* clear out reserved bits */ andc r1,r1,r3 /* PP=2 or 0, when _PAGE_HWWRITE */ mtspr RPA,r1 mfspr r3,IMISS tlbli r3 mfspr r3,SRR1 /* Need to restore CR0 */ mtcrf 0x80,r3 rfiInstructionAddressInvalid: mfspr r3,SRR1 rlwinm r1,r3,9,6,6 /* Get load/store bit */ addis r1,r1,0x2000 mtspr DSISR,r1 /* (shouldn't be needed) */ mtctr r0 /* Restore CTR */ andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ or r2,r2,r1 mtspr SRR1,r2 mfspr r1,IMISS /* Get failing address */ rlwinm. r2,r2,0,31,31 /* Check for little endian access */ rlwimi r2,r2,1,30,30 /* change 1 -> 3 */ xor r1,r1,r2 mtspr DAR,r1 /* Set fault address */ mfmsr r0 /* Restore "normal" registers */ xoris r0,r0,MSR_TGPR>>16 mtcrf 0x80,r3 /* Restore CR0 */ sync /* Some chip revs have problems here... */ mtmsr r0 b InstructionAccess/* * Handle TLB miss for DATA Load operation on 603/603e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -