/* SPDX-License-Identifier: GPL-2.0-only */ /* * Event entry/exit for Hexagon * * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*/
#include <asm/asm-offsets.h> /* assembly-safer versions of C defines */
#include <asm/mem-layout.h> /* sigh, except for page_offset */
#include <asm/hexagon_vm.h>
#include <asm/thread_info.h>
/* * Entry into guest-mode Linux under Hexagon Virtual Machine. * Stack pointer points to event record - build pt_regs on top of it, * set up a plausible C stack frame, and dispatch to the C handler. * On return, do vmrte virtual instruction with SP where we started. * * VM Spec 0.5 uses a trap to fetch HVM record now.
*/
/* * Save full register state, while setting up thread_info struct * pointer derived from kernel stack pointer in THREADINFO_REG * register, putting prior thread_info.regs pointer in a callee-save * register (R24, which had better not ever be assigned to THREADINFO_REG), * and updating thread_info.regs to point to current stack frame, * so as to support nested events in kernel mode. * * As this is common code, we set the pt_regs system call number * to -1 for all events. It will be replaced with the system call * number in the case where we decode a system call (trap0(#1)).
*/
/* * Restore registers and thread_info.regs state. THREADINFO_REG * is assumed to still be sane, and R24 to have been correctly * preserved. Don't restore R29 (SP) until later.
*/
/* * Clears off enough space for the rest of pt_regs; evrec is a part * of pt_regs in HVM mode. Save R0/R1, set handler's address in R1. * R0 is the address of pt_regs and is the parameter to save_pt_regs.
*/
/* * Since the HVM isn't automagically pushing the EVREC onto the stack anymore, * we'll subract the entire size out and then fill it in ourselves. * Need to save off R0, R1, R2, R3 immediately.
*/
.text /* * Do bulk save/restore in one place. * Adds a jump to dispatch latency, but * saves hundreds of bytes.
*/
event_dispatch:
save_pt_regs()
callr r1
/* * Coming back from the C-world, our thread info pointer * should be in the designated register (usually R19) * * If we were in kernel mode, we don't need to check scheduler * or signals if CONFIG_PREEMPTION is not set. If set, then it has * to jump to a need_resched kind of block. * BTW, CONFIG_PREEMPTION is not supported yet.
*/
/* "Nested control path" -- if the previous mode was kernel */
{
R0 = memw(R29 + #_PT_ER_VMEST);
R26.L = #LO(do_work_pending);
}
{
P0 = tstbit(R0, #HVM_VMEST_UM_SFT);
if (!P0.new) jump:nt restore_all;
R26.H = #HI(do_work_pending);
R0 = #VM_INT_DISABLE;
}
/* * Check also the return from fork/system call, normally coming back from * user mode * * R26 needs to have do_work_pending, and R0 should have VM_INT_DISABLE
*/
check_work_pending: /* Disable interrupts while checking TIF */
trap1(#HVM_TRAP1_VMSETIE)
{
R0 = R29; /* regs should still be at top of stack */
R1 = memw(THREADINFO_REG + #_THREAD_INFO_FLAGS);
callr R26;
}
restore_all: /* * Disable interrupts, if they weren't already, before reg restore. * R0 gets preloaded with #VM_INT_DISABLE before we get here.
*/
trap1(#HVM_TRAP1_VMSETIE)
/* do the setregs here for VM 0.5 */ /* R29 here should already be pointing at pt_regs */
{
R1:0 = memd(R29 + #_PT_ER_VMEL);
R3:2 = memd(R29 + #_PT_ER_VMPSP);
}
#if CONFIG_HEXAGON_ARCH_VERSION < 4
trap1(#HVM_TRAP1_VMSETREGS);
#else
G1:0 = R1:0;
G3:2 = R3:2;
#endif
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.