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, 1999, 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. regs->regs[0] = 0;
  101. /*
  102.  * This load never faults.
  103.  */
  104. __get_user(insn.word, (unsigned int *)pc);
  105. switch (insn.i_format.opcode) {
  106. /*
  107.  * These are instructions that a compiler doesn't generate.  We
  108.  * can assume therefore that the code is MIPS-aware and
  109.  * really buggy.  Emulating these instructions would break the
  110.  * semantics anyway.
  111.  */
  112. case ll_op:
  113. case lld_op:
  114. case sc_op:
  115. case scd_op:
  116. /*
  117.  * For these instructions the only way to create an address
  118.  * error is an attempted access to kernel/supervisor address
  119.  * space.
  120.  */
  121. case ldl_op:
  122. case ldr_op:
  123. case lwl_op:
  124. case lwr_op:
  125. case sdl_op:
  126. case sdr_op:
  127. case swl_op:
  128. case swr_op:
  129. case lb_op:
  130. case lbu_op:
  131. case sb_op:
  132. goto sigbus;
  133. /*
  134.  * The remaining opcodes are the ones that are really of interest.
  135.  */
  136. case lh_op:
  137. check_axs(pc, addr, 2);
  138. __asm__(
  139. ".settnoatn"
  140. #ifdef __BIG_ENDIAN
  141. "1:tlbt%0,0(%1)n"
  142. "2:tlbut$1,1(%1)nt"
  143. #endif
  144. #ifdef __LITTLE_ENDIAN
  145. "1:tlbt%0,1(%1)n"
  146. "2:tlbut$1,0(%1)nt"
  147. #endif
  148. "sllt%0,0x8nt"
  149. "ort%0,$1nt"
  150. ".settatnt"
  151. ".sectiont__ex_table,"a"nt"
  152. STR(PTR)"t1b,%2nt"
  153. STR(PTR)"t2b,%2nt"
  154. ".previous"
  155. :"=&r" (value)
  156. :"r" (addr), "i" (&&fault));
  157. regs->regs[insn.i_format.rt] = value;
  158. return 0;
  159. case lw_op:
  160. check_axs(pc, addr, 4);
  161. __asm__(
  162. #ifdef __BIG_ENDIAN
  163. "1:tlwlt%0,(%1)n"
  164. "2:tlwrt%0,3(%1)nt"
  165. #endif
  166. #ifdef __LITTLE_ENDIAN
  167. "1:tlwlt%0,3(%1)n"
  168. "2:tlwrt%0,(%1)nt"
  169. #endif
  170. ".sectiont__ex_table,"a"nt"
  171. STR(PTR)"t1b,%2nt"
  172. STR(PTR)"t2b,%2nt"
  173. ".previous"
  174. :"=&r" (value)
  175. :"r" (addr), "i" (&&fault));
  176. regs->regs[insn.i_format.rt] = value;
  177. return 0;
  178. case lhu_op:
  179. check_axs(pc, addr, 2);
  180. __asm__(
  181. ".settnoatn"
  182. #ifdef __BIG_ENDIAN
  183. "1:tlbut%0,0(%1)n"
  184. "2:tlbut$1,1(%1)nt"
  185. #endif
  186. #ifdef __LITTLE_ENDIAN
  187. "1:tlbut%0,1(%1)n"
  188. "2:tlbut$1,0(%1)nt"
  189. #endif
  190. "sllt%0,0x8nt"
  191. "ort%0,$1nt"
  192. ".settatnt"
  193. ".sectiont__ex_table,"a"nt"
  194. STR(PTR)"t1b,%2nt"
  195. STR(PTR)"t2b,%2nt"
  196. ".previous"
  197. :"=&r" (value)
  198. :"r" (addr), "i" (&&fault));
  199. regs->regs[insn.i_format.rt] = value;
  200. return 0;
  201. case lwu_op:
  202. check_axs(pc, addr, 4);
  203. __asm__(
  204. #ifdef __BIG_ENDIAN
  205. "1:tlwlt%0,(%1)n"
  206. "2:tlwrt%0,3(%1)nt"
  207. #endif
  208. #ifdef __LITTLE_ENDIAN
  209. "1:tlwlt%0,3(%1)n"
  210. "2:tlwrt%0,(%1)nt"
  211. #endif
  212. ".sectiont__ex_table,"a"nt"
  213. STR(PTR)"t1b,%2nt"
  214. STR(PTR)"t2b,%2nt"
  215. ".previous"
  216. :"=&r" (value)
  217. :"r" (addr), "i" (&&fault));
  218. value &= 0xffffffff;
  219. regs->regs[insn.i_format.rt] = value;
  220. return 0;
  221. case ld_op:
  222. check_axs(pc, addr, 8);
  223. __asm__(
  224. ".settmips3n"
  225. #ifdef __BIG_ENDIAN
  226. "1:tldlt%0,(%1)n"
  227. "2:tldrt%0,7(%1)nt"
  228. #endif
  229. #ifdef __LITTLE_ENDIAN
  230. "1:tldlt%0,7(%1)n"
  231. "2:tldrt%0,(%1)nt"
  232. #endif
  233. ".settmips0nt"
  234. ".sectiont__ex_table,"a"nt"
  235. STR(PTR)"t1b,%2nt"
  236. STR(PTR)"t2b,%2nt"
  237. ".previous"
  238. :"=&r" (value)
  239. :"r" (addr), "i" (&&fault));
  240. regs->regs[insn.i_format.rt] = value;
  241. return 0;
  242. case sh_op:
  243. check_axs(pc, addr, 2);
  244. value = regs->regs[insn.i_format.rt];
  245. __asm__(
  246. #ifdef __BIG_ENDIAN
  247. ".settnoatn"
  248. "1:tsbt%0,1(%1)nt"
  249. "srlt$1,%0,0x8n"
  250. "2:tsbt$1,0(%1)nt"
  251. ".settatnt"
  252. #endif
  253. #ifdef __LITTLE_ENDIAN
  254. ".settnoatn"
  255. "1:tsbt%0,0(%1)nt"
  256. "srlt$1,%0,0x8n"
  257. "2:tsbt$1,1(%1)nt"
  258. ".settatnt"
  259. #endif
  260. ".sectiont__ex_table,"a"nt"
  261. STR(PTR)"t1b,%2nt"
  262. STR(PTR)"t2b,%2nt"
  263. ".previous"
  264. : /* no outputs */
  265. :"r" (value), "r" (addr), "i" (&&fault));
  266. return 0;
  267. case sw_op:
  268. check_axs(pc, addr, 4);
  269. value = regs->regs[insn.i_format.rt];
  270. __asm__(
  271. #ifdef __BIG_ENDIAN
  272. "1:tswlt%0,(%1)n"
  273. "2:tswrt%0,3(%1)nt"
  274. #endif
  275. #ifdef __LITTLE_ENDIAN
  276. "1:tswlt%0,3(%1)n"
  277. "2:tswrt%0,(%1)nt"
  278. #endif
  279. ".sectiont__ex_table,"a"nt"
  280. STR(PTR)"t1b,%2nt"
  281. STR(PTR)"t2b,%2nt"
  282. ".previous"
  283. : /* no outputs */
  284. :"r" (value), "r" (addr), "i" (&&fault));
  285. return 0;
  286. case sd_op:
  287. check_axs(pc, addr, 8);
  288. value = regs->regs[insn.i_format.rt];
  289. __asm__(
  290. ".settmips3n"
  291. #ifdef __BIG_ENDIAN
  292. "1:tsdlt%0,(%1)n"
  293. "2:tsdrt%0,7(%1)nt"
  294. #endif
  295. #ifdef __LITTLE_ENDIAN
  296. "1:tsdlt%0,7(%1)n"
  297. "2:tsdrt%0,(%1)nt"
  298. #endif
  299. ".settmips0nt"
  300. ".sectiont__ex_table,"a"nt"
  301. STR(PTR)"t1b,%2nt"
  302. STR(PTR)"t2b,%2nt"
  303. ".previous"
  304. : /* no outputs */
  305. :"r" (value), "r" (addr), "i" (&&fault));
  306. return 0;
  307. case lwc1_op:
  308. case ldc1_op:
  309. case swc1_op:
  310. case sdc1_op:
  311. /*
  312.  * I herewith declare: this does not happen.  So send SIGBUS.
  313.  */
  314. goto sigbus;
  315. case lwc2_op:
  316. case ldc2_op:
  317. case swc2_op:
  318. case sdc2_op:
  319. /*
  320.  * These are the coprocessor 2 load/stores.  The current
  321.  * implementations don't use cp2 and cp2 should always be
  322.  * disabled in c0_status.  So send SIGILL.
  323.                  * (No longer true: The Sony Praystation uses cp2 for
  324.                  * 3D matrix operations.  Dunno if that thingy has a MMU ...)
  325.  */
  326. default:
  327. /*
  328.  * Pheeee...  We encountered an yet unknown instruction or
  329.  * cache coherence problem.  Die sucker, die ...
  330.  */
  331. goto sigill;
  332. }
  333. return 0;
  334. fault:
  335. /* Did we have an exception handler installed? */
  336. fixup = search_exception_table(exception_epc(regs));
  337. if (fixup) {
  338. long new_epc;
  339. new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
  340. printk(KERN_DEBUG "%s: Forwarding exception at [<%lx>] (%lx)n",
  341.        current->comm, regs->cp0_epc, new_epc);
  342. regs->cp0_epc = new_epc;
  343. return 1;
  344. }
  345. die_if_kernel ("Unhandled kernel unaligned access", regs);
  346. send_sig(SIGSEGV, current, 1);
  347. return 0;
  348. sigbus:
  349. die_if_kernel ("Unhandled kernel unaligned access", regs);
  350. send_sig(SIGBUS, current, 1);
  351. return 0;
  352. sigill:
  353. die_if_kernel ("Unhandled kernel unaligned access or invalid instruction", regs);
  354. send_sig(SIGILL, current, 1);
  355. return 0;
  356. }
  357. #ifdef CONFIG_PROC_FS
  358. unsigned long unaligned_instructions;
  359. #endif
  360. asmlinkage void do_ade(struct pt_regs *regs)
  361. {
  362. unsigned long pc;
  363. extern int do_dsemulret(struct pt_regs *);
  364. #if 0
  365.         printk("ade: Cpu%d[%s:%d:%0lx:%0lx]n", smp_processor_id(),
  366.                 current->comm, current->pid, regs->cp0_badvaddr, regs->cp0_epc);
  367. #endif
  368. /*
  369.  * Address errors may be deliberately induced
  370.  * by the FPU emulator to take retake control
  371.  * of the CPU after executing the instruction
  372.  * in the delay slot of an emulated branch.
  373.  */
  374. /* Terminate if exception was recognized as a delay slot return */
  375. if (do_dsemulret(regs))
  376. return;
  377.         /* Otherwise handle as normal */
  378. /*
  379.  * Did we catch a fault trying to load an instruction?
  380.  * This also catches attempts to activate MIPS16 code on
  381.  * CPUs which don't support it.
  382.  */
  383. if (regs->cp0_badvaddr == regs->cp0_epc)
  384. goto sigbus;
  385. pc = regs->cp0_epc + ((regs->cp0_cause & CAUSEF_BD) ? 4 : 0);
  386. if ((current->thread.mflags & MF_FIXADE) == 0)
  387. goto sigbus;
  388. /*
  389.  * Do branch emulation only if we didn't forward the exception.
  390.  * This is all so but ugly ...
  391.  */
  392. if (!emulate_load_store_insn(regs, regs->cp0_badvaddr, pc))
  393. compute_return_epc(regs);
  394. #ifdef CONFIG_PROC_FS
  395. unaligned_instructions++;
  396. #endif
  397. return;
  398. sigbus:
  399. die_if_kernel("Kernel unaligned instruction access", regs);
  400. force_sig(SIGBUS, current);
  401. }