/* entry.S: FR-V entry
*
* Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* 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.
*
*
* Entry to the kernel is "interesting":
* (1) There are no stack pointers, not even for the kernel
* (2) General Registers should not be clobbered
* (3) There are no kernel-only data registers
* (4) Since all addressing modes are wrt to a General Register, no global
* variables can be reached
*
* We deal with this by declaring that we shall kill GR28 on entering the
* kernel from userspace
*
* However, since break interrupts can interrupt the CPU even when PSR.ET==0,
* they can't rely on GR28 to be anything useful, and so need to clobber a
* separate register (GR31). Break interrupts are managed in break.S
*
* GR29 _is_ saved, and holds the current task pointer globally
*
*/
#include <linux/linkage.h>
#include <asm/thread_info.h>
#include <asm/setup.h>
#include <asm/segment.h>
#include <asm/ptrace.h>
#include <asm/errno.h>
#include <asm/cache.h>
#include <asm/spr-regs.h>
#define nr_syscalls ((syscall_table_size)/4)
.section .text..entry
.balign 4
.macro LEDS val
# sethi.p %hi(0xe1200004),gr30
# setlo %lo(0xe1200004),gr30
# setlos #~\val,gr31
# st gr31,@(gr30,gr0)
# sethi.p %hi(0xffc00100),gr30
# setlo %lo(0xffc00100),gr30
# sth gr0,@(gr30,gr0)
# membar
.endm
.macro LEDS32
# not gr31,gr31
# sethi.p %hi(0xe1200004),gr30
# setlo %lo(0xe1200004),gr30
# st.p gr31,@(gr30,gr0)
# srli gr31,#16,gr31
# sethi.p %hi(0xffc00100),gr30
# setlo %lo(0xffc00100),gr30
# sth gr31,@(gr30,gr0)
# membar
.endm
###############################################################################
#
# entry point for External interrupts received whilst executing userspace code
#
###############################################################################
.globl __entry_uspace_external_interrupt
.type __entry_uspace_external_interrupt,@function
__entry_uspace_external_interrupt:
LEDS 0x6200
sethi.p %hi(__kernel_frame0_ptr),gr28
setlo %lo(__kernel_frame0_ptr),gr28
ldi @(gr28,#0),gr28
# handle h/w single-step through exceptions
sti gr0,@(gr28,#REG__STATUS)
.globl __entry_uspace_external_interrupt_reentry
__entry_uspace_external_interrupt_reentry:
LEDS 0x6201
setlos #REG__END,gr30
dcpl gr28,gr30,#0
# finish building the exception frame
sti sp, @(gr28,#REG_SP)
stdi gr2, @(gr28,#REG_GR(2))
stdi gr4, @(gr28,#REG_GR(4))
stdi gr6, @(gr28,#REG_GR(6))
stdi gr8, @(gr28,#REG_GR(8))
stdi gr10,@(gr28,#REG_GR(10))
stdi gr12,@(gr28,#REG_GR(12))
stdi gr14,@(gr28,#REG_GR(14))
stdi gr16,@(gr28,#REG_GR(16))
stdi gr18,@(gr28,#REG_GR(18))
stdi gr20,@(gr28,#REG_GR(20))
stdi gr22,@(gr28,#REG_GR(22))
stdi gr24,@(gr28,#REG_GR(24))
stdi gr26,@(gr28,#REG_GR(26))
sti gr0, @(gr28,#REG_GR(28))
sti gr29,@(gr28,#REG_GR(29))
stdi.p gr30,@(gr28,#REG_GR(30))
# set up the kernel stack pointer
ori gr28,0,sp
movsg tbr ,gr20
movsg psr ,gr22
movsg pcsr,gr21
movsg isr ,gr23
movsg ccr ,gr24
movsg cccr,gr25
movsg lr ,gr26
movsg lcr ,gr27
setlos.p #-1,gr4
andi gr22,#PSR_PS,gr5 /* try to rebuild original PSR value */
andi.p gr22,#~(PSR_PS|PSR_S),gr6
slli gr5,#1,gr5
or gr6,gr5,gr5
andi gr5,#~PSR_ET,gr5
sti gr20,@(gr28,#REG_TBR)
sti gr21,@(gr28,#REG_PC)
sti gr5 ,@(gr28,#REG_PSR)
sti gr23,@(gr28,#REG_ISR)
stdi gr24,@(gr28,#REG_CCR)
stdi gr26,@(gr28,#REG_LR)
sti gr4 ,@(gr28,#REG_SYSCALLNO)
movsg iacc0h,gr4
movsg iacc0l,gr5
stdi gr4,@(gr28,#REG_IACC0)
movsg gner0,gr4
movsg gner1,gr5
stdi.p gr4,@(gr28,#REG_GNER0)
# interrupts start off fully disabled in the interrupt handler
subcc gr0,gr0,gr0,icc2 /* set Z and clear C */
# set up kernel global registers
sethi.p %hi(__kernel_current_task),gr5
setlo %lo(__kernel_current_task),gr5
sethi.p %hi(_gp),gr16
setlo %lo(_gp),gr16
ldi @(gr5,#0),gr29
ldi.p @(gr29,#4),gr15 ; __current_thread_info = current->thread_info
# make sure we (the kernel) get div-zero and misalignment exceptions
setlos #ISR_EDE|ISR_DTT_DIVBYZERO|ISR_EMAM_EXCEPTION,gr5
movgs gr5,isr
# switch to the kernel trap table
sethi.p %hi(__entry_kerneltrap_table),gr6
setlo %lo(__entry_kerneltrap_table),gr6
movgs gr6,tbr
# set the return address
sethi.p %hi(__entry_return_from_user_interrupt),gr4
setlo %lo(__entry_return_from_user_interrupt),gr4
movgs gr4,lr
# raise the minimum interrupt priority to 15 (NMI only) and enable exceptions
movsg psr,gr4
ori gr4,#PSR_PIL_14,gr4
movgs gr4,psr
ori gr4,#PSR_PIL_14|PSR_ET,gr4
movgs gr4,psr
LEDS 0x6202
bra do_IRQ
.size __entry_uspace_external_interrupt,.-__entry_uspace_external_interrupt
###############################################################################
#
# entry point for External interrupts received whilst executing kernel code
# - on arriving here, the following registers should already be set up:
# GR15 - current thread_info struct pointer
# GR16 - kernel GP-REL pointer
# GR29 - current task struct pointer
# TBR - kernel trap vector table
# ISR - kernel's preferred integer controls
#
###############################################################################
.globl __entry_kernel_external_interrupt
.type __entry_kernel_external_interrupt,@function
__entry_kernel_external_interrupt:
LEDS 0x6210
// sub sp,gr15,gr31
// LEDS32
# set up the stack pointer
or.p sp,gr0,gr30
subi sp,#REG__END,sp
sti gr30,@(sp,#REG_SP)
# handle h/w single-step through exceptions
sti gr0,@(sp,#REG__STATUS)
.globl __entry_kernel_external_interrupt_reentry
__entry_kernel_external_interrupt_reentry:
LEDS 0x6211
# set up the exception frame
setlos #REG__END,gr30
dcpl sp,gr30,#0
sti.p gr28,@(sp,#REG_GR(28))
ori sp,0,gr28
# finish building the exception frame
stdi gr2,@(gr28,#REG_GR(2))
stdi gr4,@(gr28,#REG_GR(4))
stdi gr6,@(gr28,#REG_GR(6))
stdi gr8,@(gr28,#REG_GR(8))
stdi gr10,@(gr28,#REG_GR(10))
stdi gr12,@(gr28,#REG_GR(12))
stdi gr14,@(gr28,#REG_GR(14))
stdi gr16,@(gr28,#REG_GR(16))
stdi gr18,@(gr28,#REG_GR(18))
stdi gr20,@(gr28,#REG_GR(20))
stdi gr22,@(gr28,#REG_GR(22))
stdi gr24,@(gr28,#REG_GR(24))
stdi gr26,@(gr28,#REG_GR(26))
sti gr29,@(gr28,#REG_GR(29))
stdi.p gr30,@(gr28,#REG_GR(30))
# note virtual interrupts will be fully enabled upon return
subicc gr0,#1,gr0,icc2 /* clear Z, set C */
movsg tbr ,gr20
movsg psr ,gr22
movsg pcsr,gr21
movsg isr ,gr23
movsg ccr ,gr24
movsg cccr,gr25
movsg lr ,gr26
movsg lcr ,gr27
setlos.p #-1,gr4
andi gr22,#PSR_PS,gr5 /* try to rebuild original PSR value */
andi.p gr22,#~(PSR_PS|PSR_S),gr6
slli gr5,#1,gr5
or gr6,gr5,gr5
andi.p gr5,#~PSR_ET,gr5
# set CCCR.CC3 to Undefined to abort atomic-modify completion inside the kernel
# - for an explanation of how it works, see: Documentation/frv/atomic-ops.txt
andi gr25,#~0xc0,gr25
sti gr20,@(gr28,#REG_TBR)
sti gr21,@(gr28,#REG_PC)
sti gr5 ,@(gr28,#REG_PSR)
sti gr23,@(gr28,#REG_ISR)
stdi gr24,@(gr28,#REG_CCR)
stdi gr26,@(gr28,#REG_LR)
sti gr4 ,@(gr28,#REG_SYSCALLNO)
movsg iacc0h,gr4
movsg iacc0l,gr5
stdi gr4,@(gr28,#REG_IACC0)
movsg gner0,gr4
movsg gner1,gr5
stdi.p gr4,@(gr28,#REG_GNER0)
# interrupts start off fully disabled in the interrupt handler
subcc gr0,gr0,gr0,icc2 /* set Z and clear C */
# set the return address
sethi.p %hi(__entry_return_from_kernel_interrupt),gr4
setlo %lo(__entry_return_from_kernel_interrupt),gr4
movgs gr4,lr
# clear power-saving mode flags
movsg hsr0,gr4
andi gr4,#~HSR0_PDM,gr4
movgs gr4,hsr0
# raise the minimu
|