get_address.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  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/vm86.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. case PREFIX_GS_ - 1:
  132. /* user gs handling can be lazy, use special accessors */
  133. addr->selector = get_user_gs(FPU_info->regs);
  134. break;
  135. default:
  136. addr->selector = PM_REG_(segment);
  137. }
  138. descriptor = FPU_get_ldt_descriptor(addr->selector);
  139. base_address = SEG_BASE_ADDR(descriptor);
  140. address = base_address + offset;
  141. limit = base_address
  142. + (SEG_LIMIT(descriptor) + 1) * SEG_GRANULARITY(descriptor) - 1;
  143. if (limit < base_address)
  144. limit = 0xffffffff;
  145. if (SEG_EXPAND_DOWN(descriptor)) {
  146. if (SEG_G_BIT(descriptor))
  147. seg_top = 0xffffffff;
  148. else {
  149. seg_top = base_address + (1 << 20);
  150. if (seg_top < base_address)
  151. seg_top = 0xffffffff;
  152. }
  153. access_limit =
  154. (address <= limit) || (address >= seg_top) ? 0 :
  155. ((seg_top - address) >= 255 ? 255 : seg_top - address);
  156. } else {
  157. access_limit =
  158. (address > limit) || (address < base_address) ? 0 :
  159. ((limit - address) >= 254 ? 255 : limit - address + 1);
  160. }
  161. if (SEG_EXECUTE_ONLY(descriptor) ||
  162. (!SEG_WRITE_PERM(descriptor) && (FPU_modrm & FPU_WRITE_BIT))) {
  163. access_limit = 0;
  164. }
  165. return address;
  166. }
  167. /*
  168. MOD R/M byte: MOD == 3 has a special use for the FPU
  169. SIB byte used iff R/M = 100b
  170. 7 6 5 4 3 2 1 0
  171. ..... ......... .........
  172. MOD OPCODE(2) R/M
  173. SIB byte
  174. 7 6 5 4 3 2 1 0
  175. ..... ......... .........
  176. SS INDEX BASE
  177. */
  178. void __user *FPU_get_address(u_char FPU_modrm, unsigned long *fpu_eip,
  179. struct address *addr, fpu_addr_modes addr_modes)
  180. {
  181. u_char mod;
  182. unsigned rm = FPU_modrm & 7;
  183. long *cpu_reg_ptr;
  184. int address = 0; /* Initialized just to stop compiler warnings. */
  185. /* Memory accessed via the cs selector is write protected
  186. in `non-segmented' 32 bit protected mode. */
  187. if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
  188. && (addr_modes.override.segment == PREFIX_CS_)) {
  189. math_abort(FPU_info, SIGSEGV);
  190. }
  191. addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
  192. mod = (FPU_modrm >> 6) & 3;
  193. if (rm == 4 && mod != 3) {
  194. address = sib(mod, fpu_eip);
  195. } else {
  196. cpu_reg_ptr = &REG_(rm);
  197. switch (mod) {
  198. case 0:
  199. if (rm == 5) {
  200. /* Special case: disp32 */
  201. RE_ENTRANT_CHECK_OFF;
  202. FPU_code_access_ok(4);
  203. FPU_get_user(address,
  204. (unsigned long __user
  205. *)(*fpu_eip));
  206. (*fpu_eip) += 4;
  207. RE_ENTRANT_CHECK_ON;
  208. addr->offset = address;
  209. return (void __user *)address;
  210. } else {
  211. address = *cpu_reg_ptr; /* Just return the contents
  212. of the cpu register */
  213. addr->offset = address;
  214. return (void __user *)address;
  215. }
  216. case 1:
  217. /* 8 bit signed displacement */
  218. RE_ENTRANT_CHECK_OFF;
  219. FPU_code_access_ok(1);
  220. FPU_get_user(address, (signed char __user *)(*fpu_eip));
  221. RE_ENTRANT_CHECK_ON;
  222. (*fpu_eip)++;
  223. break;
  224. case 2:
  225. /* 32 bit displacement */
  226. RE_ENTRANT_CHECK_OFF;
  227. FPU_code_access_ok(4);
  228. FPU_get_user(address, (long __user *)(*fpu_eip));
  229. (*fpu_eip) += 4;
  230. RE_ENTRANT_CHECK_ON;
  231. break;
  232. case 3:
  233. /* Not legal for the FPU */
  234. EXCEPTION(EX_Invalid);
  235. }
  236. address += *cpu_reg_ptr;
  237. }
  238. addr->offset = address;
  239. switch (addr_modes.default_mode) {
  240. case 0:
  241. break;
  242. case VM86:
  243. address += vm86_segment(addr_modes.override.segment, addr);
  244. break;
  245. case PM16:
  246. case SEG32:
  247. address = pm_address(FPU_modrm, addr_modes.override.segment,
  248. addr, address);
  249. break;
  250. default:
  251. EXCEPTION(EX_INTERNAL | 0x133);
  252. }
  253. return (void __user *)address;
  254. }
  255. void __user *FPU_get_address_16(u_char FPU_modrm, unsigned long *fpu_eip,
  256. struct address *addr, fpu_addr_modes addr_modes)
  257. {
  258. u_char mod;
  259. unsigned rm = FPU_modrm & 7;
  260. int address = 0; /* Default used for mod == 0 */
  261. /* Memory accessed via the cs selector is write protected
  262. in `non-segmented' 32 bit protected mode. */
  263. if (!addr_modes.default_mode && (FPU_modrm & FPU_WRITE_BIT)
  264. && (addr_modes.override.segment == PREFIX_CS_)) {
  265. math_abort(FPU_info, SIGSEGV);
  266. }
  267. addr->selector = FPU_DS; /* Default, for 32 bit non-segmented mode. */
  268. mod = (FPU_modrm >> 6) & 3;
  269. switch (mod) {
  270. case 0:
  271. if (rm == 6) {
  272. /* Special case: disp16 */
  273. RE_ENTRANT_CHECK_OFF;
  274. FPU_code_access_ok(2);
  275. FPU_get_user(address,
  276. (unsigned short __user *)(*fpu_eip));
  277. (*fpu_eip) += 2;
  278. RE_ENTRANT_CHECK_ON;
  279. goto add_segment;
  280. }
  281. break;
  282. case 1:
  283. /* 8 bit signed displacement */
  284. RE_ENTRANT_CHECK_OFF;
  285. FPU_code_access_ok(1);
  286. FPU_get_user(address, (signed char __user *)(*fpu_eip));
  287. RE_ENTRANT_CHECK_ON;
  288. (*fpu_eip)++;
  289. break;
  290. case 2:
  291. /* 16 bit displacement */
  292. RE_ENTRANT_CHECK_OFF;
  293. FPU_code_access_ok(2);
  294. FPU_get_user(address, (unsigned short __user *)(*fpu_eip));
  295. (*fpu_eip) += 2;
  296. RE_ENTRANT_CHECK_ON;
  297. break;
  298. case 3:
  299. /* Not legal for the FPU */
  300. EXCEPTION(EX_Invalid);
  301. break;
  302. }
  303. switch (rm) {
  304. case 0:
  305. address += FPU_info->regs->bx + FPU_info->regs->si;
  306. break;
  307. case 1:
  308. address += FPU_info->regs->bx + FPU_info->regs->di;
  309. break;
  310. case 2:
  311. address += FPU_info->regs->bp + FPU_info->regs->si;
  312. if (addr_modes.override.segment == PREFIX_DEFAULT)
  313. addr_modes.override.segment = PREFIX_SS_;
  314. break;
  315. case 3:
  316. address += FPU_info->regs->bp + FPU_info->regs->di;
  317. if (addr_modes.override.segment == PREFIX_DEFAULT)
  318. addr_modes.override.segment = PREFIX_SS_;
  319. break;
  320. case 4:
  321. address += FPU_info->regs->si;
  322. break;
  323. case 5:
  324. address += FPU_info->regs->di;
  325. break;
  326. case 6:
  327. address += FPU_info->regs->bp;
  328. if (addr_modes.override.segment == PREFIX_DEFAULT)
  329. addr_modes.override.segment = PREFIX_SS_;
  330. break;
  331. case 7:
  332. address += FPU_info->regs->bx;
  333. break;
  334. }
  335. add_segment:
  336. address &= 0xffff;
  337. addr->offset = address;
  338. switch (addr_modes.default_mode) {
  339. case 0:
  340. break;
  341. case VM86:
  342. address += vm86_segment(addr_modes.override.segment, addr);
  343. break;
  344. case PM16:
  345. case SEG32:
  346. address = pm_address(FPU_modrm, addr_modes.override.segment,
  347. addr, address);
  348. break;
  349. default:
  350. EXCEPTION(EX_INTERNAL | 0x131);
  351. }
  352. return (void __user *)address;
  353. }