unaligned.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:10k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Handle unaligned accesses by emulation.
  3.  *
  4.  * This file is subject to the terms and conditions of the GNU General Public
  5.  * License.  See the file "COPYING" in the main directory of this archive
  6.  * for more details.
  7.  *
  8.  * Copyright (C) 1996, 1998, 2002 by Ralf Baechle
  9.  * Copyright (C) 1999 Silicon Graphics, Inc.
  10.  *
  11.  * This file contains exception handler for address error exception with the
  12.  * special capability to execute faulting instructions in software.  The
  13.  * handler does not try to handle the case when the program counter points
  14.  * to an address not aligned to a word boundary.
  15.  *
  16.  * Putting data to unaligned addresses is a bad practice even on Intel where
  17.  * only the performance is affected.  Much worse is that such code is non-
  18.  * portable.  Due to several programs that die on MIPS due to alignment
  19.  * problems I decided to implement this handler anyway though I originally
  20.  * didn't intend to do this at all for user code.
  21.  *
  22.  * For now I enable fixing of address errors by default to make life easier.
  23.  * I however intend to disable this somewhen in the future when the alignment
  24.  * problems with user programs have been fixed.  For programmers this is the
  25.  * right way to go.
  26.  *
  27.  * Fixing address errors is a per process option.  The option is inherited
  28.  * across fork(2) and execve(2) calls.  If you really want to use the
  29.  * option in your user programs - I discourage the use of the software
  30.  * emulation strongly - use the following code in your userland stuff:
  31.  *
  32.  * #include <sys/sysmips.h>
  33.  *
  34.  * ...
  35.  * sysmips(MIPS_FIXADE, x);
  36.  * ...
  37.  *
  38.  * The argument x is 0 for disabling software emulation, enabled otherwise.
  39.  *
  40.  * Below a little program to play around with this feature.
  41.  *
  42.  * #include <stdio.h>
  43.  * #include <asm/sysmips.h>
  44.  *
  45.  * struct foo {
  46.  *         unsigned char bar[8];
  47.  * };
  48.  *
  49.  * main(int argc, char *argv[])
  50.  * {
  51.  *         struct foo x = {0, 1, 2, 3, 4, 5, 6, 7};
  52.  *         unsigned int *p = (unsigned int *) (x.bar + 3);
  53.  *         int i;
  54.  *
  55.  *         if (argc > 1)
  56.  *                 sysmips(MIPS_FIXADE, atoi(argv[1]));
  57.  *
  58.  *         printf("*p = %08lxn", *p);
  59.  *
  60.  *         *p = 0xdeadface;
  61.  *
  62.  *         for(i = 0; i <= 7; i++)
  63.  *         printf("%02x ", x.bar[i]);
  64.  *         printf("n");
  65.  * }
  66.  *
  67.  * Coprocessor loads are not supported; I think this case is unimportant
  68.  * in the practice.
  69.  *
  70.  * TODO: Handle ndc (attempted store to doubleword in uncached memory)
  71.  *       exception for the R6000.
  72.  *       A store crossing a page boundary might be executed only partially.
  73.  *       Undo the partial store in this case.
  74.  */
  75. #include <linux/config.h>
  76. #include <linux/mm.h>
  77. #include <linux/signal.h>
  78. #include <linux/smp.h>
  79. #include <linux/smp_lock.h>
  80. #include <asm/asm.h>
  81. #include <asm/branch.h>
  82. #include <asm/byteorder.h>
  83. #include <asm/inst.h>
  84. #include <asm/uaccess.h>
  85. #include <asm/system.h>
  86. #define STR(x)  __STR(x)
  87. #define __STR(x)  #x
  88. /*
  89.  * User code may only access USEG; kernel code may access the
  90.  * entire address space.
  91.  */
  92. #define check_axs(pc,a,s)
  93. if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0)
  94. goto sigbus;
  95. static inline int emulate_load_store_insn(struct pt_regs *regs,
  96. unsigned long addr, unsigned long pc)
  97. {
  98. union mips_instruction insn;
  99. unsigned long value, fixup;
  100. unsigned int res;
  101. regs->regs[0] = 0;
  102. /*
  103.  * This load never faults.
  104.  */
  105. __get_user(insn.word, (unsigned int *)pc);
  106. switch (insn.i_format.opcode) {
  107. /*
  108.  * These are instructions that a compiler doesn't generate.  We
  109.  * can assume therefore that the code is MIPS-aware and
  110.  * really buggy.  Emulating these instructions would break the
  111.  * semantics anyway.
  112.  */
  113. case ll_op:
  114. case lld_op:
  115. case sc_op:
  116. case scd_op:
  117. /*
  118.  * For these instructions the only way to create an address
  119.  * error is an attempted access to kernel/supervisor address
  120.  * space.
  121.  */
  122. case ldl_op:
  123. case ldr_op:
  124. case lwl_op:
  125. case lwr_op:
  126. case sdl_op:
  127. case sdr_op:
  128. case swl_op:
  129. case swr_op:
  130. case lb_op:
  131. case lbu_op:
  132. case sb_op:
  133. goto sigbus;
  134. /*
  135.  * The remaining opcodes are the ones that are really of interest.
  136.  */
  137. case lh_op:
  138. check_axs(pc, addr, 2);
  139. __asm__(".settnoatn"
  140. #ifdef __BIG_ENDIAN
  141. "1:tlbt%0, 0(%2)n"
  142. "2:tlbut$1, 1(%2)nt"
  143. #endif
  144. #ifdef __LITTLE_ENDIAN
  145. "1:tlbt%0, 1(%2)n"
  146. "2:tlbut$1, 0(%2)nt"
  147. #endif
  148. "sllt%0, 0x8nt"
  149. "ort%0, $1nt"
  150. "lit%1, 0n"
  151. "3:t.settatnt"
  152. ".sectiont.fixup,"ax"nt"
  153. "4:tlit%1, %3nt"
  154. "jt3bnt"
  155. ".previousnt"
  156. ".sectiont__ex_table,"a"nt"
  157. STR(PTR)"t1b, 4bnt"
  158. STR(PTR)"t2b, 4bnt"
  159. ".previous"
  160. : "=&r" (value), "=r" (res)
  161. : "r" (addr), "i" (-EFAULT));
  162. if (res)
  163. goto fault;
  164. regs->regs[insn.i_format.rt] = value;
  165. return 0;
  166. case lw_op:
  167. check_axs(pc, addr, 4);
  168. __asm__(
  169. #ifdef __BIG_ENDIAN
  170. "1:tlwlt%0, (%2)n"
  171. "2:tlwrt%0, 3(%2)nt"
  172. #endif
  173. #ifdef __LITTLE_ENDIAN
  174. "1:tlwlt%0, 3(%2)n"
  175. "2:tlwrt%0, (%2)nt"
  176. #endif
  177. "lit%1, 0n"
  178. "3:t.sectiont.fixup,"ax"nt"
  179. "4:tlit%1, %3nt"
  180. "jt3bnt"
  181. ".previousnt"
  182. ".sectiont__ex_table,"a"nt"
  183. STR(PTR)"t1b, 4bnt"
  184. STR(PTR)"t2b, 4bnt"
  185. ".previous"
  186. : "=&r" (value), "=r" (res)
  187. : "r" (addr), "i" (-EFAULT));
  188. if (res)
  189. goto fault;
  190. regs->regs[insn.i_format.rt] = value;
  191. return 0;
  192. case lhu_op:
  193. check_axs(pc, addr, 2);
  194. __asm__(
  195. ".settnoatn"
  196. #ifdef __BIG_ENDIAN
  197. "1:tlbut%0, 0(%2)n"
  198. "2:tlbut$1, 1(%2)nt"
  199. #endif
  200. #ifdef __LITTLE_ENDIAN
  201. "1:tlbut%0, 1(%2)n"
  202. "2:tlbut$1, 0(%2)nt"
  203. #endif
  204. "sllt%0, 0x8nt"
  205. "ort%0, $1nt"
  206. "lit%1, 0n"
  207. "3:t.settatnt"
  208. ".sectiont.fixup,"ax"nt"
  209. "4:tlit%1, %3nt"
  210. "jt3bnt"
  211. ".previousnt"
  212. ".sectiont__ex_table,"a"nt"
  213. STR(PTR)"t1b, 4bnt"
  214. STR(PTR)"t2b, 4bnt"
  215. ".previous"
  216. : "=&r" (value), "=r" (res)
  217. : "r" (addr), "i" (-EFAULT));
  218. if (res)
  219. goto fault;
  220. regs->regs[insn.i_format.rt] = value;
  221. return 0;
  222. case lwu_op:
  223. case ld_op:
  224. /* Cannot handle 64-bit instructions in 32-bit kernel */
  225. goto sigill;
  226. case sh_op:
  227. check_axs(pc, addr, 2);
  228. value = regs->regs[insn.i_format.rt];
  229. __asm__(
  230. #ifdef __BIG_ENDIAN
  231. ".settnoatn"
  232. "1:tsbt%1, 1(%2)nt"
  233. "srlt$1, %1, 0x8n"
  234. "2:tsbt$1, 0(%2)nt"
  235. ".settatnt"
  236. #endif
  237. #ifdef __LITTLE_ENDIAN
  238. ".settnoatn"
  239. "1:tsbt%1, 0(%2)nt"
  240. "srlt$1,%1, 0x8n"
  241. "2:tsbt$1, 1(%2)nt"
  242. ".settatnt"
  243. #endif
  244. "lit%0, 0n"
  245. "3:nt"
  246. ".sectiont.fixup,"ax"nt"
  247. "4:tlit%0, %3nt"
  248. "jt3bnt"
  249. ".previousnt"
  250. ".sectiont__ex_table,"a"nt"
  251. STR(PTR)"t1b, 4bnt"
  252. STR(PTR)"t2b, 4bnt"
  253. ".previous"
  254. : "=r" (res)
  255. : "r" (value), "r" (addr), "i" (-EFAULT));
  256. if (res)
  257. goto fault;
  258. return 0;
  259. case sw_op:
  260. check_axs(pc, addr, 4);
  261. value = regs->regs[insn.i_format.rt];
  262. __asm__(
  263. #ifdef __BIG_ENDIAN
  264. "1:tswlt%1,(%2)n"
  265. "2:tswrt%1, 3(%2)nt"
  266. #endif
  267. #ifdef __LITTLE_ENDIAN
  268. "1:tswlt%1, 3(%2)n"
  269. "2:tswrt%1, (%2)nt"
  270. #endif
  271. "lit%0, 0n"
  272. "3:nt"
  273. ".sectiont.fixup,"ax"nt"
  274. "4:tlit%0, %3nt"
  275. "jt3bnt"
  276. ".previousnt"
  277. ".sectiont__ex_table,"a"nt"
  278. STR(PTR)"t1b, 4bnt"
  279. STR(PTR)"t2b, 4bnt"
  280. ".previous"
  281. : "=r" (res)
  282. : "r" (value), "r" (addr), "i" (-EFAULT));
  283. if (res)
  284. goto fault;
  285. return 0;
  286. case sd_op:
  287. /* Cannot handle 64-bit instructions in 32-bit kernel */
  288. goto sigill;
  289. case lwc1_op:
  290. case ldc1_op:
  291. case swc1_op:
  292. case sdc1_op:
  293. /*
  294.  * I herewith declare: this does not happen.  So send SIGBUS.
  295.  */
  296. goto sigbus;
  297. case lwc2_op:
  298. case ldc2_op:
  299. case swc2_op:
  300. case sdc2_op:
  301. /*
  302.  * These are the coprocessor 2 load/stores.  The current
  303.  * implementations don't use cp2 and cp2 should always be
  304.  * disabled in c0_status.  So send SIGILL.
  305.                  * (No longer true: The Sony Praystation uses cp2 for
  306.                  * 3D matrix operations.  Dunno if that thingy has a MMU ...)
  307.  */
  308. default:
  309. /*
  310.  * Pheeee...  We encountered an yet unknown instruction or
  311.  * cache coherence problem.  Die sucker, die ...
  312.  */
  313. goto sigill;
  314. }
  315. return 0;
  316. fault:
  317. /* Did we have an exception handler installed? */
  318. fixup = search_exception_table(exception_epc(regs));
  319. if (fixup) {
  320. long new_epc;
  321. new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
  322. printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)n",
  323.        current->comm, regs->cp0_epc, new_epc);
  324. regs->cp0_epc = new_epc;
  325. return 1;
  326. }
  327. die_if_kernel ("Unhandled kernel unaligned access", regs);
  328. send_sig(SIGSEGV, current, 1);
  329. return 0;
  330. sigbus:
  331. die_if_kernel("Unhandled kernel unaligned access", regs);
  332. send_sig(SIGBUS, current, 1);
  333. return 0;
  334. sigill:
  335. die_if_kernel("Unhandled kernel unaligned access or invalid instruction", regs);
  336. send_sig(SIGILL, current, 1);
  337. return 0;
  338. }
  339. #ifdef CONFIG_PROC_FS
  340. unsigned long unaligned_instructions;
  341. #endif
  342. asmlinkage void do_ade(struct pt_regs *regs)
  343. {
  344. unsigned long pc;
  345. extern int do_dsemulret(struct pt_regs *);
  346. /*
  347.  * Address errors may be deliberately induced
  348.  * by the FPU emulator to take retake control
  349.  * of the CPU after executing the instruction
  350.  * in the delay slot of an emulated branch.
  351.  */
  352. /* Terminate if exception was recognized as a delay slot return */
  353. if (do_dsemulret(regs))
  354. return;
  355. /* Otherwise handle as normal */
  356. /*
  357.  * Did we catch a fault trying to load an instruction?
  358.  * This also catches attempts to activate MIPS16 code on
  359.  * CPUs which don't support it.
  360.  */
  361. if (regs->cp0_badvaddr == regs->cp0_epc)
  362. goto sigbus;
  363. pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
  364. if ((current->thread.mflags & MF_FIXADE) == 0)
  365. goto sigbus;
  366. /*
  367.  * Do branch emulation only if we didn't forward the exception.
  368.  * This is all so but ugly ...
  369.  */
  370. if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc))
  371. compute_return_epc(regs);
  372. #ifdef CONFIG_PROC_FS
  373. unaligned_instructions++;
  374. #endif
  375. return;
  376. sigbus:
  377. die_if_kernel("Kernel unaligned instruction access", regs);
  378. force_sig(SIGBUS, current);
  379. /*
  380.  * XXX On return from the signal handler we should advance the epc
  381.  */
  382. return;
  383. }