mirror of https://gitee.com/openkylin/linux.git
131 lines
3.5 KiB
ArmAsm
131 lines
3.5 KiB
ArmAsm
/*
|
|
* Assembly Language Functions for MIPS MT SMTC support
|
|
*/
|
|
|
|
/*
|
|
* This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set. */
|
|
|
|
#include <asm/regdef.h>
|
|
#include <asm/asmmacro.h>
|
|
#include <asm/stackframe.h>
|
|
#include <asm/irqflags.h>
|
|
|
|
/*
|
|
* "Software Interrupt" linkage.
|
|
*
|
|
* This is invoked when an "Interrupt" is sent from one TC to another,
|
|
* where the TC to be interrupted is halted, has it's Restart address
|
|
* and Status values saved by the "remote control" thread, then modified
|
|
* to cause execution to begin here, in kenel mode. This code then
|
|
* disguises the TC state as that of an exception and transfers
|
|
* control to the general exception or vectored interrupt handler.
|
|
*/
|
|
.set noreorder
|
|
|
|
/*
|
|
The __smtc_ipi_vector would use k0 and k1 as temporaries and
|
|
1) Set EXL (this is per-VPE, so this can't be done by proxy!)
|
|
2) Restore the K/CU and IXMT bits to the pre "exception" state
|
|
(EXL means no interrupts and access to the kernel map).
|
|
3) Set EPC to be the saved value of TCRestart.
|
|
4) Jump to the exception handler entry point passed by the sender.
|
|
|
|
CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
|
|
*/
|
|
|
|
/*
|
|
* Reviled and slandered vision: Set EXL and restore K/CU/IXMT
|
|
* state of pre-halt thread, then save everything and call
|
|
* thought some function pointer to imaginary_exception, which
|
|
* will parse a register value or memory message queue to
|
|
* deliver things like interprocessor interrupts. On return
|
|
* from that function, jump to the global ret_from_irq code
|
|
* to invoke the scheduler and return as appropriate.
|
|
*/
|
|
|
|
#define PT_PADSLOT4 (PT_R0-8)
|
|
#define PT_PADSLOT5 (PT_R0-4)
|
|
|
|
.text
|
|
.align 5
|
|
FEXPORT(__smtc_ipi_vector)
|
|
.set noat
|
|
/* Disable thread scheduling to make Status update atomic */
|
|
DMT 27 # dmt k1
|
|
_ehb
|
|
/* Set EXL */
|
|
mfc0 k0,CP0_STATUS
|
|
ori k0,k0,ST0_EXL
|
|
mtc0 k0,CP0_STATUS
|
|
_ehb
|
|
/* Thread scheduling now inhibited by EXL. Restore TE state. */
|
|
andi k1,k1,VPECONTROL_TE
|
|
beqz k1,1f
|
|
emt
|
|
1:
|
|
/*
|
|
* The IPI sender has put some information on the anticipated
|
|
* kernel stack frame. If we were in user mode, this will be
|
|
* built above the saved kernel SP. If we were already in the
|
|
* kernel, it will be built above the current CPU SP.
|
|
*
|
|
* Were we in kernel mode, as indicated by CU0?
|
|
*/
|
|
sll k1,k0,3
|
|
.set noreorder
|
|
bltz k1,2f
|
|
move k1,sp
|
|
.set reorder
|
|
/*
|
|
* If previously in user mode, set CU0 and use kernel stack.
|
|
*/
|
|
li k1,ST0_CU0
|
|
or k1,k1,k0
|
|
mtc0 k1,CP0_STATUS
|
|
_ehb
|
|
get_saved_sp
|
|
/* Interrupting TC will have pre-set values in slots in the new frame */
|
|
2: subu k1,k1,PT_SIZE
|
|
/* Load TCStatus Value */
|
|
lw k0,PT_TCSTATUS(k1)
|
|
/* Write it to TCStatus to restore CU/KSU/IXMT state */
|
|
mtc0 k0,$2,1
|
|
_ehb
|
|
lw k0,PT_EPC(k1)
|
|
mtc0 k0,CP0_EPC
|
|
/* Save all will redundantly recompute the SP, but use it for now */
|
|
SAVE_ALL
|
|
CLI
|
|
TRACE_IRQS_OFF
|
|
/* Function to be invoked passed stack pad slot 5 */
|
|
lw t0,PT_PADSLOT5(sp)
|
|
/* Argument from sender passed in stack pad slot 4 */
|
|
lw a0,PT_PADSLOT4(sp)
|
|
LONG_L s0, TI_REGS($28)
|
|
LONG_S sp, TI_REGS($28)
|
|
PTR_LA ra, ret_from_irq
|
|
jr t0
|
|
|
|
/*
|
|
* Called from idle loop to provoke processing of queued IPIs
|
|
* First IPI message in queue passed as argument.
|
|
*/
|
|
|
|
LEAF(self_ipi)
|
|
/* Before anything else, block interrupts */
|
|
mfc0 t0,CP0_TCSTATUS
|
|
ori t1,t0,TCSTATUS_IXMT
|
|
mtc0 t1,CP0_TCSTATUS
|
|
_ehb
|
|
/* We know we're in kernel mode, so prepare stack frame */
|
|
subu t1,sp,PT_SIZE
|
|
sw ra,PT_EPC(t1)
|
|
sw a0,PT_PADSLOT4(t1)
|
|
la t2,ipi_decode
|
|
sw t2,PT_PADSLOT5(t1)
|
|
/* Save pre-disable value of TCStatus */
|
|
sw t0,PT_TCSTATUS(t1)
|
|
j __smtc_ipi_vector
|
|
nop
|
|
END(self_ipi)
|