162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * File:	mca_asm.h
462306a36Sopenharmony_ci * Purpose:	Machine check handling specific defines
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1999 Silicon Graphics, Inc.
762306a36Sopenharmony_ci * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
862306a36Sopenharmony_ci * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
962306a36Sopenharmony_ci * Copyright (C) 2000 Hewlett-Packard Co.
1062306a36Sopenharmony_ci * Copyright (C) 2000 David Mosberger-Tang <davidm@hpl.hp.com>
1162306a36Sopenharmony_ci * Copyright (C) 2002 Intel Corp.
1262306a36Sopenharmony_ci * Copyright (C) 2002 Jenna Hall <jenna.s.hall@intel.com>
1362306a36Sopenharmony_ci * Copyright (C) 2005 Silicon Graphics, Inc
1462306a36Sopenharmony_ci * Copyright (C) 2005 Keith Owens <kaos@sgi.com>
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci#ifndef _ASM_IA64_MCA_ASM_H
1762306a36Sopenharmony_ci#define _ASM_IA64_MCA_ASM_H
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <asm/percpu.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define PSR_IC		13
2262306a36Sopenharmony_ci#define PSR_I		14
2362306a36Sopenharmony_ci#define	PSR_DT		17
2462306a36Sopenharmony_ci#define PSR_RT		27
2562306a36Sopenharmony_ci#define PSR_MC		35
2662306a36Sopenharmony_ci#define PSR_IT		36
2762306a36Sopenharmony_ci#define PSR_BN		44
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci/*
3062306a36Sopenharmony_ci * This macro converts a instruction virtual address to a physical address
3162306a36Sopenharmony_ci * Right now for simulation purposes the virtual addresses are
3262306a36Sopenharmony_ci * direct mapped to physical addresses.
3362306a36Sopenharmony_ci *	1. Lop off bits 61 thru 63 in the virtual address
3462306a36Sopenharmony_ci */
3562306a36Sopenharmony_ci#define INST_VA_TO_PA(addr)							\
3662306a36Sopenharmony_ci	dep	addr	= 0, addr, 61, 3
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * This macro converts a data virtual address to a physical address
3962306a36Sopenharmony_ci * Right now for simulation purposes the virtual addresses are
4062306a36Sopenharmony_ci * direct mapped to physical addresses.
4162306a36Sopenharmony_ci *	1. Lop off bits 61 thru 63 in the virtual address
4262306a36Sopenharmony_ci */
4362306a36Sopenharmony_ci#define DATA_VA_TO_PA(addr)							\
4462306a36Sopenharmony_ci	tpa	addr	= addr
4562306a36Sopenharmony_ci/*
4662306a36Sopenharmony_ci * This macro converts a data physical address to a virtual address
4762306a36Sopenharmony_ci * Right now for simulation purposes the virtual addresses are
4862306a36Sopenharmony_ci * direct mapped to physical addresses.
4962306a36Sopenharmony_ci *	1. Put 0x7 in bits 61 thru 63.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci#define DATA_PA_TO_VA(addr,temp)							\
5262306a36Sopenharmony_ci	mov	temp	= 0x7	;;							\
5362306a36Sopenharmony_ci	dep	addr	= temp, addr, 61, 3
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define GET_THIS_PADDR(reg, var)		\
5662306a36Sopenharmony_ci	mov	reg = IA64_KR(PER_CPU_DATA);;	\
5762306a36Sopenharmony_ci        addl	reg = THIS_CPU(var), reg
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * This macro jumps to the instruction at the given virtual address
6162306a36Sopenharmony_ci * and starts execution in physical mode with all the address
6262306a36Sopenharmony_ci * translations turned off.
6362306a36Sopenharmony_ci *	1.	Save the current psr
6462306a36Sopenharmony_ci *	2.	Make sure that all the upper 32 bits are off
6562306a36Sopenharmony_ci *
6662306a36Sopenharmony_ci *	3.	Clear the interrupt enable and interrupt state collection bits
6762306a36Sopenharmony_ci *		in the psr before updating the ipsr and iip.
6862306a36Sopenharmony_ci *
6962306a36Sopenharmony_ci *	4.	Turn off the instruction, data and rse translation bits of the psr
7062306a36Sopenharmony_ci *		and store the new value into ipsr
7162306a36Sopenharmony_ci *		Also make sure that the interrupts are disabled.
7262306a36Sopenharmony_ci *		Ensure that we are in little endian mode.
7362306a36Sopenharmony_ci *		[psr.{rt, it, dt, i, be} = 0]
7462306a36Sopenharmony_ci *
7562306a36Sopenharmony_ci *	5.	Get the physical address corresponding to the virtual address
7662306a36Sopenharmony_ci *		of the next instruction bundle and put it in iip.
7762306a36Sopenharmony_ci *		(Using magic numbers 24 and 40 in the deposint instruction since
7862306a36Sopenharmony_ci *		 the IA64_SDK code directly maps to lower 24bits as physical address
7962306a36Sopenharmony_ci *		 from a virtual address).
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci *	6.	Do an rfi to move the values from ipsr to psr and iip to ip.
8262306a36Sopenharmony_ci */
8362306a36Sopenharmony_ci#define  PHYSICAL_MODE_ENTER(temp1, temp2, start_addr, old_psr)				\
8462306a36Sopenharmony_ci	mov	old_psr = psr;								\
8562306a36Sopenharmony_ci	;;										\
8662306a36Sopenharmony_ci	dep	old_psr = 0, old_psr, 32, 32;						\
8762306a36Sopenharmony_ci											\
8862306a36Sopenharmony_ci	mov	ar.rsc = 0 ;								\
8962306a36Sopenharmony_ci	;;										\
9062306a36Sopenharmony_ci	srlz.d;										\
9162306a36Sopenharmony_ci	mov	temp2 = ar.bspstore;							\
9262306a36Sopenharmony_ci	;;										\
9362306a36Sopenharmony_ci	DATA_VA_TO_PA(temp2);								\
9462306a36Sopenharmony_ci	;;										\
9562306a36Sopenharmony_ci	mov	temp1 = ar.rnat;							\
9662306a36Sopenharmony_ci	;;										\
9762306a36Sopenharmony_ci	mov	ar.bspstore = temp2;							\
9862306a36Sopenharmony_ci	;;										\
9962306a36Sopenharmony_ci	mov	ar.rnat = temp1;							\
10062306a36Sopenharmony_ci	mov	temp1 = psr;								\
10162306a36Sopenharmony_ci	mov	temp2 = psr;								\
10262306a36Sopenharmony_ci	;;										\
10362306a36Sopenharmony_ci											\
10462306a36Sopenharmony_ci	dep	temp2 = 0, temp2, PSR_IC, 2;						\
10562306a36Sopenharmony_ci	;;										\
10662306a36Sopenharmony_ci	mov	psr.l = temp2;								\
10762306a36Sopenharmony_ci	;;										\
10862306a36Sopenharmony_ci	srlz.d;										\
10962306a36Sopenharmony_ci	dep	temp1 = 0, temp1, 32, 32;						\
11062306a36Sopenharmony_ci	;;										\
11162306a36Sopenharmony_ci	dep	temp1 = 0, temp1, PSR_IT, 1;						\
11262306a36Sopenharmony_ci	;;										\
11362306a36Sopenharmony_ci	dep	temp1 = 0, temp1, PSR_DT, 1;						\
11462306a36Sopenharmony_ci	;;										\
11562306a36Sopenharmony_ci	dep	temp1 = 0, temp1, PSR_RT, 1;						\
11662306a36Sopenharmony_ci	;;										\
11762306a36Sopenharmony_ci	dep	temp1 = 0, temp1, PSR_I, 1;						\
11862306a36Sopenharmony_ci	;;										\
11962306a36Sopenharmony_ci	dep	temp1 = 0, temp1, PSR_IC, 1;						\
12062306a36Sopenharmony_ci	;;										\
12162306a36Sopenharmony_ci	dep	temp1 = -1, temp1, PSR_MC, 1;						\
12262306a36Sopenharmony_ci	;;										\
12362306a36Sopenharmony_ci	mov	cr.ipsr = temp1;							\
12462306a36Sopenharmony_ci	;;										\
12562306a36Sopenharmony_ci	LOAD_PHYSICAL(p0, temp2, start_addr);						\
12662306a36Sopenharmony_ci	;;										\
12762306a36Sopenharmony_ci	mov	cr.iip = temp2;								\
12862306a36Sopenharmony_ci	mov	cr.ifs = r0;								\
12962306a36Sopenharmony_ci	DATA_VA_TO_PA(sp);								\
13062306a36Sopenharmony_ci	DATA_VA_TO_PA(gp);								\
13162306a36Sopenharmony_ci	;;										\
13262306a36Sopenharmony_ci	srlz.i;										\
13362306a36Sopenharmony_ci	;;										\
13462306a36Sopenharmony_ci	nop	1;									\
13562306a36Sopenharmony_ci	nop	2;									\
13662306a36Sopenharmony_ci	nop	1;									\
13762306a36Sopenharmony_ci	nop	2;									\
13862306a36Sopenharmony_ci	rfi;										\
13962306a36Sopenharmony_ci	;;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * This macro jumps to the instruction at the given virtual address
14362306a36Sopenharmony_ci * and starts execution in virtual mode with all the address
14462306a36Sopenharmony_ci * translations turned on.
14562306a36Sopenharmony_ci *	1.	Get the old saved psr
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci *	2.	Clear the interrupt state collection bit in the current psr.
14862306a36Sopenharmony_ci *
14962306a36Sopenharmony_ci *	3.	Set the instruction translation bit back in the old psr
15062306a36Sopenharmony_ci *		Note we have to do this since we are right now saving only the
15162306a36Sopenharmony_ci *		lower 32-bits of old psr.(Also the old psr has the data and
15262306a36Sopenharmony_ci *		rse translation bits on)
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci *	4.	Set ipsr to this old_psr with "it" bit set and "bn" = 1.
15562306a36Sopenharmony_ci *
15662306a36Sopenharmony_ci *	5.	Reset the current thread pointer (r13).
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci *	6.	Set iip to the virtual address of the next instruction bundle.
15962306a36Sopenharmony_ci *
16062306a36Sopenharmony_ci *	7.	Do an rfi to move ipsr to psr and iip to ip.
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define VIRTUAL_MODE_ENTER(temp1, temp2, start_addr, old_psr)	\
16462306a36Sopenharmony_ci	mov	temp2 = psr;					\
16562306a36Sopenharmony_ci	;;							\
16662306a36Sopenharmony_ci	mov	old_psr = temp2;				\
16762306a36Sopenharmony_ci	;;							\
16862306a36Sopenharmony_ci	dep	temp2 = 0, temp2, PSR_IC, 2;			\
16962306a36Sopenharmony_ci	;;							\
17062306a36Sopenharmony_ci	mov	psr.l = temp2;					\
17162306a36Sopenharmony_ci	mov	ar.rsc = 0;					\
17262306a36Sopenharmony_ci	;;							\
17362306a36Sopenharmony_ci	srlz.d;							\
17462306a36Sopenharmony_ci	mov	r13 = ar.k6;					\
17562306a36Sopenharmony_ci	mov	temp2 = ar.bspstore;				\
17662306a36Sopenharmony_ci	;;							\
17762306a36Sopenharmony_ci	DATA_PA_TO_VA(temp2,temp1);				\
17862306a36Sopenharmony_ci	;;							\
17962306a36Sopenharmony_ci	mov	temp1 = ar.rnat;				\
18062306a36Sopenharmony_ci	;;							\
18162306a36Sopenharmony_ci	mov	ar.bspstore = temp2;				\
18262306a36Sopenharmony_ci	;;							\
18362306a36Sopenharmony_ci	mov	ar.rnat = temp1;				\
18462306a36Sopenharmony_ci	;;							\
18562306a36Sopenharmony_ci	mov	temp1 = old_psr;				\
18662306a36Sopenharmony_ci	;;							\
18762306a36Sopenharmony_ci	mov	temp2 = 1;					\
18862306a36Sopenharmony_ci	;;							\
18962306a36Sopenharmony_ci	dep	temp1 = temp2, temp1, PSR_IC, 1;		\
19062306a36Sopenharmony_ci	;;							\
19162306a36Sopenharmony_ci	dep	temp1 = temp2, temp1, PSR_IT, 1;		\
19262306a36Sopenharmony_ci	;;							\
19362306a36Sopenharmony_ci	dep	temp1 = temp2, temp1, PSR_DT, 1;		\
19462306a36Sopenharmony_ci	;;							\
19562306a36Sopenharmony_ci	dep	temp1 = temp2, temp1, PSR_RT, 1;		\
19662306a36Sopenharmony_ci	;;							\
19762306a36Sopenharmony_ci	dep	temp1 = temp2, temp1, PSR_BN, 1;		\
19862306a36Sopenharmony_ci	;;							\
19962306a36Sopenharmony_ci								\
20062306a36Sopenharmony_ci	mov     cr.ipsr = temp1;				\
20162306a36Sopenharmony_ci	movl	temp2 = start_addr;				\
20262306a36Sopenharmony_ci	;;							\
20362306a36Sopenharmony_ci	mov	cr.iip = temp2;					\
20462306a36Sopenharmony_ci	movl	gp = __gp					\
20562306a36Sopenharmony_ci	;;							\
20662306a36Sopenharmony_ci	DATA_PA_TO_VA(sp, temp1);				\
20762306a36Sopenharmony_ci	srlz.i;							\
20862306a36Sopenharmony_ci	;;							\
20962306a36Sopenharmony_ci	nop	1;						\
21062306a36Sopenharmony_ci	nop	2;						\
21162306a36Sopenharmony_ci	nop	1;						\
21262306a36Sopenharmony_ci	rfi							\
21362306a36Sopenharmony_ci	;;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci/*
21662306a36Sopenharmony_ci * The MCA and INIT stacks in struct ia64_mca_cpu look like normal kernel
21762306a36Sopenharmony_ci * stacks, except that the SAL/OS state and a switch_stack are stored near the
21862306a36Sopenharmony_ci * top of the MCA/INIT stack.  To support concurrent entry to MCA or INIT, as
21962306a36Sopenharmony_ci * well as MCA over INIT, each event needs its own SAL/OS state.  All entries
22062306a36Sopenharmony_ci * are 16 byte aligned.
22162306a36Sopenharmony_ci *
22262306a36Sopenharmony_ci *      +---------------------------+
22362306a36Sopenharmony_ci *      |          pt_regs          |
22462306a36Sopenharmony_ci *      +---------------------------+
22562306a36Sopenharmony_ci *      |        switch_stack       |
22662306a36Sopenharmony_ci *      +---------------------------+
22762306a36Sopenharmony_ci *      |        SAL/OS state       |
22862306a36Sopenharmony_ci *      +---------------------------+
22962306a36Sopenharmony_ci *      |    16 byte scratch area   |
23062306a36Sopenharmony_ci *      +---------------------------+ <-------- SP at start of C MCA handler
23162306a36Sopenharmony_ci *      |           .....           |
23262306a36Sopenharmony_ci *      +---------------------------+
23362306a36Sopenharmony_ci *      | RBS for MCA/INIT handler  |
23462306a36Sopenharmony_ci *      +---------------------------+
23562306a36Sopenharmony_ci *      | struct task for MCA/INIT  |
23662306a36Sopenharmony_ci *      +---------------------------+ <-------- Bottom of MCA/INIT stack
23762306a36Sopenharmony_ci */
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci#define ALIGN16(x)			((x)&~15)
24062306a36Sopenharmony_ci#define MCA_PT_REGS_OFFSET		ALIGN16(KERNEL_STACK_SIZE-IA64_PT_REGS_SIZE)
24162306a36Sopenharmony_ci#define MCA_SWITCH_STACK_OFFSET		ALIGN16(MCA_PT_REGS_OFFSET-IA64_SWITCH_STACK_SIZE)
24262306a36Sopenharmony_ci#define MCA_SOS_OFFSET			ALIGN16(MCA_SWITCH_STACK_OFFSET-IA64_SAL_OS_STATE_SIZE)
24362306a36Sopenharmony_ci#define MCA_SP_OFFSET			ALIGN16(MCA_SOS_OFFSET-16)
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#endif /* _ASM_IA64_MCA_ASM_H */
246