get_address.c 11 KB

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