18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle
78c2ecf20Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Protected memory access.  Used for everything that might take revenge
108c2ecf20Sopenharmony_ci * by sending a DBE error like accessing possibly non-existent memory or
118c2ecf20Sopenharmony_ci * devices.
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci#ifndef _ASM_PACCESS_H
148c2ecf20Sopenharmony_ci#define _ASM_PACCESS_H
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/errno.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#ifdef CONFIG_32BIT
198c2ecf20Sopenharmony_ci#define __PA_ADDR	".word"
208c2ecf20Sopenharmony_ci#endif
218c2ecf20Sopenharmony_ci#ifdef CONFIG_64BIT
228c2ecf20Sopenharmony_ci#define __PA_ADDR	".dword"
238c2ecf20Sopenharmony_ci#endif
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ciextern asmlinkage void handle_ibe(void);
268c2ecf20Sopenharmony_ciextern asmlinkage void handle_dbe(void);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define put_dbe(x, ptr) __put_dbe((x), (ptr), sizeof(*(ptr)))
298c2ecf20Sopenharmony_ci#define get_dbe(x, ptr) __get_dbe((x), (ptr), sizeof(*(ptr)))
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct __large_pstruct { unsigned long buf[100]; };
328c2ecf20Sopenharmony_ci#define __mp(x) (*(struct __large_pstruct *)(x))
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define __get_dbe(x, ptr, size)						\
358c2ecf20Sopenharmony_ci({									\
368c2ecf20Sopenharmony_ci	long __gu_err;							\
378c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __gu_val;					\
388c2ecf20Sopenharmony_ci	unsigned long __gu_addr;					\
398c2ecf20Sopenharmony_ci	__asm__("":"=r" (__gu_val));					\
408c2ecf20Sopenharmony_ci	__gu_addr = (unsigned long) (ptr);				\
418c2ecf20Sopenharmony_ci	__asm__("":"=r" (__gu_err));					\
428c2ecf20Sopenharmony_ci	switch (size) {							\
438c2ecf20Sopenharmony_ci	case 1: __get_dbe_asm("lb"); break;				\
448c2ecf20Sopenharmony_ci	case 2: __get_dbe_asm("lh"); break;				\
458c2ecf20Sopenharmony_ci	case 4: __get_dbe_asm("lw"); break;				\
468c2ecf20Sopenharmony_ci	case 8:	 __get_dbe_asm("ld"); break;				\
478c2ecf20Sopenharmony_ci	default: __get_dbe_unknown(); break;				\
488c2ecf20Sopenharmony_ci	}								\
498c2ecf20Sopenharmony_ci	x = (__typeof__(*(ptr))) __gu_val;				\
508c2ecf20Sopenharmony_ci	__gu_err;							\
518c2ecf20Sopenharmony_ci})
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#define __get_dbe_asm(insn)						\
548c2ecf20Sopenharmony_ci{									\
558c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
568c2ecf20Sopenharmony_ci	"1:\t" insn "\t%1,%2\n\t"					\
578c2ecf20Sopenharmony_ci	"move\t%0,$0\n"							\
588c2ecf20Sopenharmony_ci	"2:\n\t"							\
598c2ecf20Sopenharmony_ci	".insn\n\t"							\
608c2ecf20Sopenharmony_ci	".section\t.fixup,\"ax\"\n"					\
618c2ecf20Sopenharmony_ci	"3:\tli\t%0,%3\n\t"						\
628c2ecf20Sopenharmony_ci	"move\t%1,$0\n\t"						\
638c2ecf20Sopenharmony_ci	"j\t2b\n\t"							\
648c2ecf20Sopenharmony_ci	".previous\n\t"							\
658c2ecf20Sopenharmony_ci	".section\t__dbe_table,\"a\"\n\t"				\
668c2ecf20Sopenharmony_ci	__PA_ADDR "\t1b, 3b\n\t"					\
678c2ecf20Sopenharmony_ci	".previous"							\
688c2ecf20Sopenharmony_ci	:"=r" (__gu_err), "=r" (__gu_val)				\
698c2ecf20Sopenharmony_ci	:"o" (__mp(__gu_addr)), "i" (-EFAULT));				\
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciextern void __get_dbe_unknown(void);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci#define __put_dbe(x, ptr, size)						\
758c2ecf20Sopenharmony_ci({									\
768c2ecf20Sopenharmony_ci	long __pu_err;							\
778c2ecf20Sopenharmony_ci	__typeof__(*(ptr)) __pu_val;					\
788c2ecf20Sopenharmony_ci	long __pu_addr;							\
798c2ecf20Sopenharmony_ci	__pu_val = (x);							\
808c2ecf20Sopenharmony_ci	__pu_addr = (long) (ptr);					\
818c2ecf20Sopenharmony_ci	__asm__("":"=r" (__pu_err));					\
828c2ecf20Sopenharmony_ci	switch (size) {							\
838c2ecf20Sopenharmony_ci	case 1: __put_dbe_asm("sb"); break;				\
848c2ecf20Sopenharmony_ci	case 2: __put_dbe_asm("sh"); break;				\
858c2ecf20Sopenharmony_ci	case 4: __put_dbe_asm("sw"); break;				\
868c2ecf20Sopenharmony_ci	case 8: __put_dbe_asm("sd"); break;				\
878c2ecf20Sopenharmony_ci	default: __put_dbe_unknown(); break;				\
888c2ecf20Sopenharmony_ci	}								\
898c2ecf20Sopenharmony_ci	__pu_err;							\
908c2ecf20Sopenharmony_ci})
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define __put_dbe_asm(insn)						\
938c2ecf20Sopenharmony_ci{									\
948c2ecf20Sopenharmony_ci	__asm__ __volatile__(						\
958c2ecf20Sopenharmony_ci	"1:\t" insn "\t%1,%2\n\t"					\
968c2ecf20Sopenharmony_ci	"move\t%0,$0\n"							\
978c2ecf20Sopenharmony_ci	"2:\n\t"							\
988c2ecf20Sopenharmony_ci	".insn\n\t"							\
998c2ecf20Sopenharmony_ci	".section\t.fixup,\"ax\"\n"					\
1008c2ecf20Sopenharmony_ci	"3:\tli\t%0,%3\n\t"						\
1018c2ecf20Sopenharmony_ci	"j\t2b\n\t"							\
1028c2ecf20Sopenharmony_ci	".previous\n\t"							\
1038c2ecf20Sopenharmony_ci	".section\t__dbe_table,\"a\"\n\t"				\
1048c2ecf20Sopenharmony_ci	__PA_ADDR "\t1b, 3b\n\t"					\
1058c2ecf20Sopenharmony_ci	".previous"							\
1068c2ecf20Sopenharmony_ci	: "=r" (__pu_err)						\
1078c2ecf20Sopenharmony_ci	: "r" (__pu_val), "o" (__mp(__pu_addr)), "i" (-EFAULT));	\
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciextern void __put_dbe_unknown(void);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ciextern unsigned long search_dbe_table(unsigned long addr);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci#endif /* _ASM_PACCESS_H */
115