162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 1996, 1997, 1998, 1999, 2000 by Ralf Baechle 762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Protected memory access. Used for everything that might take revenge 1062306a36Sopenharmony_ci * by sending a DBE error like accessing possibly non-existent memory or 1162306a36Sopenharmony_ci * devices. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci#ifndef _ASM_PACCESS_H 1462306a36Sopenharmony_ci#define _ASM_PACCESS_H 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/errno.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#ifdef CONFIG_32BIT 1962306a36Sopenharmony_ci#define __PA_ADDR ".word" 2062306a36Sopenharmony_ci#endif 2162306a36Sopenharmony_ci#ifdef CONFIG_64BIT 2262306a36Sopenharmony_ci#define __PA_ADDR ".dword" 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciextern asmlinkage void handle_ibe(void); 2662306a36Sopenharmony_ciextern asmlinkage void handle_dbe(void); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define put_dbe(x, ptr) __put_dbe((x), (ptr), sizeof(*(ptr))) 2962306a36Sopenharmony_ci#define get_dbe(x, ptr) __get_dbe((x), (ptr), sizeof(*(ptr))) 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct __large_pstruct { unsigned long buf[100]; }; 3262306a36Sopenharmony_ci#define __mp(x) (*(struct __large_pstruct *)(x)) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define __get_dbe(x, ptr, size) \ 3562306a36Sopenharmony_ci({ \ 3662306a36Sopenharmony_ci long __gu_err; \ 3762306a36Sopenharmony_ci __typeof__(*(ptr)) __gu_val; \ 3862306a36Sopenharmony_ci unsigned long __gu_addr; \ 3962306a36Sopenharmony_ci __asm__("":"=r" (__gu_val)); \ 4062306a36Sopenharmony_ci __gu_addr = (unsigned long) (ptr); \ 4162306a36Sopenharmony_ci __asm__("":"=r" (__gu_err)); \ 4262306a36Sopenharmony_ci switch (size) { \ 4362306a36Sopenharmony_ci case 1: __get_dbe_asm("lb"); break; \ 4462306a36Sopenharmony_ci case 2: __get_dbe_asm("lh"); break; \ 4562306a36Sopenharmony_ci case 4: __get_dbe_asm("lw"); break; \ 4662306a36Sopenharmony_ci case 8: __get_dbe_asm("ld"); break; \ 4762306a36Sopenharmony_ci default: __get_dbe_unknown(); break; \ 4862306a36Sopenharmony_ci } \ 4962306a36Sopenharmony_ci x = (__typeof__(*(ptr))) __gu_val; \ 5062306a36Sopenharmony_ci __gu_err; \ 5162306a36Sopenharmony_ci}) 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define __get_dbe_asm(insn) \ 5462306a36Sopenharmony_ci{ \ 5562306a36Sopenharmony_ci __asm__ __volatile__( \ 5662306a36Sopenharmony_ci "1:\t" insn "\t%1,%2\n\t" \ 5762306a36Sopenharmony_ci "move\t%0,$0\n" \ 5862306a36Sopenharmony_ci "2:\n\t" \ 5962306a36Sopenharmony_ci ".insn\n\t" \ 6062306a36Sopenharmony_ci ".section\t.fixup,\"ax\"\n" \ 6162306a36Sopenharmony_ci "3:\tli\t%0,%3\n\t" \ 6262306a36Sopenharmony_ci "move\t%1,$0\n\t" \ 6362306a36Sopenharmony_ci "j\t2b\n\t" \ 6462306a36Sopenharmony_ci ".previous\n\t" \ 6562306a36Sopenharmony_ci ".section\t__dbe_table,\"a\"\n\t" \ 6662306a36Sopenharmony_ci __PA_ADDR "\t1b, 3b\n\t" \ 6762306a36Sopenharmony_ci ".previous" \ 6862306a36Sopenharmony_ci :"=r" (__gu_err), "=r" (__gu_val) \ 6962306a36Sopenharmony_ci :"o" (__mp(__gu_addr)), "i" (-EFAULT)); \ 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciextern void __get_dbe_unknown(void); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define __put_dbe(x, ptr, size) \ 7562306a36Sopenharmony_ci({ \ 7662306a36Sopenharmony_ci long __pu_err; \ 7762306a36Sopenharmony_ci __typeof__(*(ptr)) __pu_val; \ 7862306a36Sopenharmony_ci long __pu_addr; \ 7962306a36Sopenharmony_ci __pu_val = (x); \ 8062306a36Sopenharmony_ci __pu_addr = (long) (ptr); \ 8162306a36Sopenharmony_ci __asm__("":"=r" (__pu_err)); \ 8262306a36Sopenharmony_ci switch (size) { \ 8362306a36Sopenharmony_ci case 1: __put_dbe_asm("sb"); break; \ 8462306a36Sopenharmony_ci case 2: __put_dbe_asm("sh"); break; \ 8562306a36Sopenharmony_ci case 4: __put_dbe_asm("sw"); break; \ 8662306a36Sopenharmony_ci case 8: __put_dbe_asm("sd"); break; \ 8762306a36Sopenharmony_ci default: __put_dbe_unknown(); break; \ 8862306a36Sopenharmony_ci } \ 8962306a36Sopenharmony_ci __pu_err; \ 9062306a36Sopenharmony_ci}) 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define __put_dbe_asm(insn) \ 9362306a36Sopenharmony_ci{ \ 9462306a36Sopenharmony_ci __asm__ __volatile__( \ 9562306a36Sopenharmony_ci "1:\t" insn "\t%1,%2\n\t" \ 9662306a36Sopenharmony_ci "move\t%0,$0\n" \ 9762306a36Sopenharmony_ci "2:\n\t" \ 9862306a36Sopenharmony_ci ".insn\n\t" \ 9962306a36Sopenharmony_ci ".section\t.fixup,\"ax\"\n" \ 10062306a36Sopenharmony_ci "3:\tli\t%0,%3\n\t" \ 10162306a36Sopenharmony_ci "j\t2b\n\t" \ 10262306a36Sopenharmony_ci ".previous\n\t" \ 10362306a36Sopenharmony_ci ".section\t__dbe_table,\"a\"\n\t" \ 10462306a36Sopenharmony_ci __PA_ADDR "\t1b, 3b\n\t" \ 10562306a36Sopenharmony_ci ".previous" \ 10662306a36Sopenharmony_ci : "=r" (__pu_err) \ 10762306a36Sopenharmony_ci : "r" (__pu_val), "o" (__mp(__pu_addr)), "i" (-EFAULT)); \ 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ciextern void __put_dbe_unknown(void); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ciextern unsigned long search_dbe_table(unsigned long addr); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#endif /* _ASM_PACCESS_H */ 115