get_address.c 11 KB

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