get_address.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*---------------------------------------------------------------------------+
  2. | get_address.c |
  3. | |
  4. | Get the effective address from an FPU instruction. |
  5. | |
  6. | Copyright (C) 1992,1993,1994,1997 |
  7. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
  8. | Australia. E-mail billm@suburbia.net |
  9. | |
  10. | |
  11. +---------------------------------------------------------------------------*/
  12. /*---------------------------------------------------------------------------+
  13. | Note: |
  14. | The file contains code which accesses user memory. |
  15. | Emulator static data may change when user memory is accessed, due to |
  16. | other processes using the emulator while swapping is in progress. |
  17. +---------------------------------------------------------------------------*/
  18. #include <linux/stddef.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/desc.h>
  21. #include "fpu_system.h"
  22. #include "exception.h"
  23. #include "fpu_emu.h"
  24. #define FPU_WRITE_BIT 0x10
  25. static int reg_offset[] = {
  26. offsetof(struct pt_regs, ax),
  27. offsetof(struct pt_regs, cx),
  28. offsetof(struct pt_regs, dx),
  29. offsetof(struct pt_regs, bx),
  30. offsetof(struct pt_regs, sp),
  31. offsetof(struct pt_regs, bp),
  32. offsetof(struct pt_regs, si),
  33. offsetof(struct pt_regs, di)
  34. };
  35. #define REG_(x) (*(long *)(reg_offset[(x)] + (u_char *)FPU_info->regs))
  36. static int reg_offset_vm86[] = {
  37. offsetof(struct pt_regs, cs),
  38. offsetof(struct kernel_vm86_regs, ds),
  39. offsetof(struct kernel_vm86_regs, es),
  40. offsetof(struct kernel_vm86_regs, fs),
  41. offsetof(struct kernel_vm86_regs, gs),
  42. offsetof(struct pt_regs, ss),
  43. offsetof(struct kernel_vm86_regs, ds)
  44. };
  45. #define VM86_REG_(x) (*(unsigned short *) \
  46. (reg_offset_vm86[((unsigned)x)] + (u_char *)FPU_info->regs))
  47. static int reg_offset_pm[] = {
  48. offsetof(struct pt_regs, cs),
  49. offsetof(struct pt_regs, ds),
  50. offsetof(struct pt_regs, es),
  51. offsetof(struct pt_regs, fs),
  52. offsetof(struct pt_regs, ds), /* dummy, not saved on stack */
  53. offsetof(struct pt_regs, ss),
  54. offsetof(struct pt_regs, ds)
  55. };
  56. #define PM_REG_(x) (*(unsigned short *) \
  57. (reg_offset_pm[((unsigned)x)] + (u_char *)FPU_info->regs))
  58. /* Decode the SIB byte. This function assumes mod != 0 */
  59. static int sib(int mod, unsigned long *fpu_eip)
  60. {
  61. u_char ss, index, base;
  62. long offset;
  63. RE_ENTRANT_CHECK_OFF;
  64. FPU_code_access_ok(1);
  65. FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
  66. RE_ENTRANT_CHECK_ON;
  67. (*fpu_eip)++;
  68. ss = base >> 6;
  69. index = (base >> 3) & 7;
  70. base &= 7;
  71. if ((mod == 0) && (base == 5))
  72. offset = 0; /* No base register */
  73. else
  74. offset = REG_(base);
  75. if (index == 4) {
  76. /* No index register */
  77. /* A non-zero ss is illegal */
  78. if (ss)
  79. EXCEPTION(EX_Invalid);
  80. } else {
  81. offset += (REG_(index)) << ss;
  82. }
  83. if (mod == 1) {
  84. /* 8 bit signed displacement */
  85. long displacement;
  86. RE_ENTRANT_CHECK_OFF;
  87. FPU_code_access_ok(1);
  88. FPU_get_user(displacement, (signed char __user *)(*fpu_eip));
  89. offset += displacement;
  90. RE_ENTRANT_CHECK_ON;
  91. (*fpu_eip)++;
  92. } else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */
  93. /* 32 bit displacement */
  94. long displacement;
  95. RE_ENTRANT_CHECK_OFF;
  96. FPU_code_access_ok(4);
  97. FPU_get_user(displacement, (long __user *)(*fpu_eip));
  98. offset += displacement;
  99. RE_ENTRANT_CHECK_ON;
  100. (*fpu_eip) += 4;
  101. }
  102. return offset;
  103. }
  104. static unsigned long vm86_segment(u_char segment, struct address *addr)
  105. {
  106. segment--;
  107. #ifdef PARANOID
  108. if (segment > PREFIX_SS_) {
  109. EXCEPTION(EX_INTERNAL | 0x130);
  110. math_abort(FPU_info, SIGSEGV);
  111. }
  112. #endif /* PARANOID */
  113. addr->selector = VM86_REG_(segment);
  114. return (unsigned long)VM86_REG_(segment) << 4;
  115. }
  116. /* This should work for 16 and 32 bit protected mode. */
  117. static long pm_address(u_char FPU_modrm, u_char segment,
  118. struct address *addr, long offset)
  119. {
  120. struct desc_struct descriptor;
  121. unsigned long base_address, limit, address, seg_top;
  122. segment--;
  123. #ifdef PARANOID
  124. /* segment is unsigned, so this also detects if segment was 0: */
  125. if (segment > PREFIX_SS_) {
  126. EXCEPTION(EX_INTERNAL | 0x132);
  127. math_abort(FPU_info, SIGSEGV);
  128. }
  129. #endif /* PARANOID */
  130. switch (segment) {
  131. /* gs isn't used by the kernel, so it still has its
  132. user-space value. */
  133. case PREFIX_GS_ - 1:
  134. /* N.B. - movl %seg, mem is a 2 byte write regardless of prefix */
  135. savesegment(gs, addr->selector);
  136. break;
  137. default:
  138. addr->selector = PM_REG_(segment);
  139. }
  140. descriptor = LDT_DESCRIPTOR(PM_REG_(segment));
  141. base_address = SEG_BASE_ADDR(descriptor);
  142. address = base_address + offset;
  143. limit = base_address
  144. + (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1;
  145. if (limit < base_address)
  146. limit = 0xffffffff;
  147. if (SEG_EXPAND_DOWN(descriptor)) {
  148. if (SEG_G_BIT(descriptor))
  149. seg_top = 0xffffffff;
  150. else {
  151. seg_top = base_address + (1 << 20);
  152. if (seg_top < base_address)
  153. seg_top = 0xffffffff;
  154. }
  155. access_limit =
  156. (address <= limit) || (address >= seg_top) ? 0 :
  157. ((seg_top - address) >= 255 ? 255 : seg_top - address);
  158. } else {
  159. access_limit =
  160. (address > limit) || (address < base_address) ? 0 :
  161. ((limit - address) >= 254 ? 255 : limit - address + 1);
  162. }
  163. if (SEG_EXECUTE_ONLY(descriptor) ||
  164. (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
  165. access_limit = 0;
  166. }
  167. return address;
  168. }
  169. /*
  170. MOD R/M byte: MOD == 3 has a special use for the FPU
  171. SIB byte used iff R/M = 100b
  172. 7 6 5 4 3 2 1 0
  173. ..... ......... .........
  174. MOD OPCODE(2) R/M
  175. SIB byte
  176. 7 6 5 4 3 2 1 0
  177. ..... ......... .........
  178. SS INDEX BASE
  179. */
  180. void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
  181. struct address *addr, fpu_addr_modes addr_modes)
  182. {
  183. u_char mod;
  184. unsigned rm = FPU_modrm & 7;
  185. long *cpu_reg_ptr;
  186. int address = 0; /* Initialized just to stop compiler warnings. */
  187. /* Memory accessed via the cs selector is write protected
  188. in `non-segmented' 32 bit protected mode. */
  189. if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
  190. && (addr_modes.override.segment == PREFIX_CS_)) {
  191. math_abort(FPU_info, SIGSEGV);
  192. }
  193. addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
  194. mod = (FPU_modrm >> 6) & 3;
  195. if (rm == 4 && mod != 3) {
  196. address = sib(mod, fpu_eip);
  197. } else {
  198. cpu_reg_ptr = &REG_(rm);
  199. switch (mod) {
  200. case 0:
  201. if (rm == 5) {
  202. /* Special case: disp32 */
  203. RE_ENTRANT_CHECK_OFF;
  204. FPU_code_access_ok(4);
  205. FPU_get_user(address,
  206. (unsigned long __user
  207. *)(*fpu_eip));
  208. (*fpu_eip) += 4;
  209. RE_ENTRANT_CHECK_ON;
  210. addr->offset = address;
  211. return (void __user *)address;
  212. } else {
  213. address = *cpu_reg_ptr; /* Just return the contents
  214. of the cpu register */
  215. addr->offset = address;
  216. return (void __user *)address;
  217. }
  218. case 1:
  219. /* 8 bit signed displacement */
  220. RE_ENTRANT_CHECK_OFF;
  221. FPU_code_access_ok(1);
  222. FPU_get_user(address, (signed char __user *)(*fpu_eip));
  223. RE_ENTRANT_CHECK_ON;
  224. (*fpu_eip)++;
  225. break;
  226. case 2:
  227. /* 32 bit displacement */
  228. RE_ENTRANT_CHECK_OFF;
  229. FPU_code_access_ok(4);
  230. FPU_get_user(address, (long __user *)(*fpu_eip));
  231. (*fpu_eip) += 4;
  232. RE_ENTRANT_CHECK_ON;
  233. break;
  234. case 3:
  235. /* Not legal for the FPU */
  236. EXCEPTION(EX_Invalid);
  237. }
  238. address += *cpu_reg_ptr;
  239. }
  240. addr->offset = address;
  241. switch (addr_modes.default_mode) {
  242. case 0:
  243. break;
  244. case VM86:
  245. address += vm86_segment(addr_modes.override.segment, addr);
  246. break;
  247. case PM16:
  248. case SEG32:
  249. address = pm_address(FPU_modrm, addr_modes.override.segment,
  250. addr, address);
  251. break;
  252. default:
  253. EXCEPTION(EX_INTERNAL | 0x133);
  254. }
  255. return (void __user *)address;
  256. }
  257. void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
  258. struct address *addr, fpu_addr_modes addr_modes)
  259. {
  260. u_char mod;
  261. unsigned rm = FPU_modrm & 7;
  262. int address = 0; /* Default used for mod == 0 */
  263. /* Memory accessed via the cs selector is write protected
  264. in `non-segmented' 32 bit protected mode. */
  265. if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
  266. && (addr_modes.override.segment == PREFIX_CS_)) {
  267. math_abort(FPU_info, SIGSEGV);
  268. }
  269. addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
  270. mod = (FPU_modrm >> 6) & 3;
  271. switch (mod) {
  272. case 0:
  273. if (rm == 6) {
  274. /* Special case: disp16 */
  275. RE_ENTRANT_CHECK_OFF;
  276. FPU_code_access_ok(2);
  277. FPU_get_user(address,
  278. (unsigned short __user *)(*fpu_eip));
  279. (*fpu_eip) += 2;
  280. RE_ENTRANT_CHECK_ON;
  281. goto add_segment;
  282. }
  283. break;
  284. case 1:
  285. /* 8 bit signed displacement */
  286. RE_ENTRANT_CHECK_OFF;
  287. FPU_code_access_ok(1);
  288. FPU_get_user(address, (signed char __user *)(*fpu_eip));
  289. RE_ENTRANT_CHECK_ON;
  290. (*fpu_eip)++;
  291. break;
  292. case 2:
  293. /* 16 bit displacement */
  294. RE_ENTRANT_CHECK_OFF;
  295. FPU_code_access_ok(2);
  296. FPU_get_user(address, (unsigned short __user *)(*fpu_eip));
  297. (*fpu_eip) += 2;
  298. RE_ENTRANT_CHECK_ON;
  299. break;
  300. case 3:
  301. /* Not legal for the FPU */
  302. EXCEPTION(EX_Invalid);
  303. break;
  304. }
  305. switch (rm) {
  306. case 0:
  307. address += FPU_info->regs->bx + FPU_info->regs->si;
  308. break;
  309. case 1:
  310. address += FPU_info->regs->bx + FPU_info->regs->di;
  311. break;
  312. case 2:
  313. address += FPU_info->regs->bp + FPU_info->regs->si;
  314. if (addr_modes.override.segment == PREFIX_DEFAULT)
  315. addr_modes.override.segment = PREFIX_SS_;
  316. break;
  317. case 3:
  318. address += FPU_info->regs->bp + FPU_info->regs->di;
  319. if (addr_modes.override.segment == PREFIX_DEFAULT)
  320. addr_modes.override.segment = PREFIX_SS_;
  321. break;
  322. case 4:
  323. address += FPU_info->regs->si;
  324. break;
  325. case 5:
  326. address += FPU_info->regs->di;
  327. break;
  328. case 6:
  329. address += FPU_info->regs->bp;
  330. if (addr_modes.override.segment == PREFIX_DEFAULT)
  331. addr_modes.override.segment = PREFIX_SS_;
  332. break;
  333. case 7:
  334. address += FPU_info->regs->bx;
  335. break;
  336. }
  337. add_segment:
  338. address &= 0xffff;
  339. addr->offset = address;
  340. switch (addr_modes.default_mode) {
  341. case 0:
  342. break;
  343. case VM86:
  344. address += vm86_segment(addr_modes.override.segment, addr);
  345. break;
  346. case PM16:
  347. case SEG32:
  348. address = pm_address(FPU_modrm, addr_modes.override.segment,
  349. addr, address);
  350. break;
  351. default:
  352. EXCEPTION(EX_INTERNAL | 0x131);
  353. }
  354. return (void __user *)address;
  355. }