get_address.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*---------------------------------------------------------------------------+
  3. | get_address.c |
  4. | |
  5. | Get the effective address from an FPU instruction. |
  6. | |
  7. | Copyright (C) 1992,1993,1994,1997 |
  8. | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
  9. | Australia. E-mail billm@suburbia.net |
  10. | |
  11. | |
  12. +---------------------------------------------------------------------------*/
  13. /*---------------------------------------------------------------------------+
  14. | Note: |
  15. | The file contains code which accesses user memory. |
  16. | Emulator static data may change when user memory is accessed, due to |
  17. | other processes using the emulator while swapping is in progress. |
  18. +---------------------------------------------------------------------------*/
  19. #include <linux/stddef.h>
  20. #include <linux/uaccess.h>
  21. #include <asm/vm86.h>
  22. #include "fpu_system.h"
  23. #include "exception.h"
  24. #include "fpu_emu.h"
  25. #define FPU_WRITE_BIT 0x10
  26. static int reg_offset[] = {
  27. offsetof(struct pt_regs, ax),
  28. offsetof(struct pt_regs, cx),
  29. offsetof(struct pt_regs, dx),
  30. offsetof(struct pt_regs, bx),
  31. offsetof(struct pt_regs, sp),
  32. offsetof(struct pt_regs, bp),
  33. offsetof(struct pt_regs, si),
  34. offsetof(struct pt_regs, di)
  35. };
  36. #define REG_(x) (*(long *)(reg_offset[(x)] + (u_char *)FPU_info->regs))
  37. static int reg_offset_vm86[] = {
  38. offsetof(struct pt_regs, cs),
  39. offsetof(struct kernel_vm86_regs, ds),
  40. offsetof(struct kernel_vm86_regs, es),
  41. offsetof(struct kernel_vm86_regs, fs),
  42. offsetof(struct kernel_vm86_regs, gs),
  43. offsetof(struct pt_regs, ss),
  44. offsetof(struct kernel_vm86_regs, ds)
  45. };
  46. #define VM86_REG_(x) (*(unsigned short *) \
  47. (reg_offset_vm86[((unsigned)x)] + (u_char *)FPU_info->regs))
  48. static int reg_offset_pm[] = {
  49. offsetof(struct pt_regs, cs),
  50. offsetof(struct pt_regs, ds),
  51. offsetof(struct pt_regs, es),
  52. offsetof(struct pt_regs, fs),
  53. offsetof(struct pt_regs, ds), /* dummy, not saved on stack */
  54. offsetof(struct pt_regs, ss),
  55. offsetof(struct pt_regs, ds)
  56. };
  57. #define PM_REG_(x) (*(unsigned short *) \
  58. (reg_offset_pm[((unsigned)x)] + (u_char *)FPU_info->regs))
  59. /* Decode the SIB byte. This function assumes mod != 0 */
  60. static int sib(int mod, unsigned long *fpu_eip)
  61. {
  62. u_char ss, index, base;
  63. long offset;
  64. RE_ENTRANT_CHECK_OFF;
  65. FPU_code_access_ok(1);
  66. FPU_get_user(base, (u_char __user *) (*fpu_eip)); /* The SIB byte */
  67. RE_ENTRANT_CHECK_ON;
  68. (*fpu_eip)++;
  69. ss = base >> 6;
  70. index = (base >> 3) & 7;
  71. base &= 7;
  72. if ((mod == 0) && (base == 5))
  73. offset = 0; /* No base register */
  74. else
  75. offset = REG_(base);
  76. if (index == 4) {
  77. /* No index register */
  78. /* A non-zero ss is illegal */
  79. if (ss)
  80. EXCEPTION(EX_Invalid);
  81. } else {
  82. offset += (REG_(index)) << ss;
  83. }
  84. if (mod == 1) {
  85. /* 8 bit signed displacement */
  86. long displacement;
  87. RE_ENTRANT_CHECK_OFF;
  88. FPU_code_access_ok(1);
  89. FPU_get_user(displacement, (signed char __user *)(*fpu_eip));
  90. offset += displacement;
  91. RE_ENTRANT_CHECK_ON;
  92. (*fpu_eip)++;
  93. } else if (mod == 2 || base == 5) { /* The second condition also has mod==0 */
  94. /* 32 bit displacement */
  95. long displacement;
  96. RE_ENTRANT_CHECK_OFF;
  97. FPU_code_access_ok(4);
  98. FPU_get_user(displacement, (long __user *)(*fpu_eip));
  99. offset += displacement;
  100. RE_ENTRANT_CHECK_ON;
  101. (*fpu_eip) += 4;
  102. }
  103. return offset;
  104. }
  105. static unsigned long vm86_segment(u_char segment, struct address *addr)
  106. {
  107. segment--;
  108. #ifdef PARANOID
  109. if (segment > PREFIX_SS_) {
  110. EXCEPTION(EX_INTERNAL | 0x130);
  111. math_abort(FPU_info, SIGSEGV);
  112. }
  113. #endif /* PARANOID */
  114. addr->selector = VM86_REG_(segment);
  115. return (unsigned long)VM86_REG_(segment) << 4;
  116. }
  117. /* This should work for 16 and 32 bit protected mode. */
  118. static long pm_address(u_char FPU_modrm, u_char segment,
  119. struct address *addr, long offset)
  120. {
  121. struct desc_struct descriptor;
  122. unsigned long base_address, limit, address, seg_top;
  123. segment--;
  124. #ifdef PARANOID
  125. /* segment is unsigned, so this also detects if segment was 0: */
  126. if (segment > PREFIX_SS_) {
  127. EXCEPTION(EX_INTERNAL | 0x132);
  128. math_abort(FPU_info, SIGSEGV);
  129. }
  130. #endif /* PARANOID */
  131. switch (segment) {
  132. case PREFIX_GS_ - 1:
  133. /* user gs handling can be lazy, use special accessors */
  134. addr->selector = get_user_gs(FPU_info->regs);
  135. break;
  136. default:
  137. addr->selector = PM_REG_(segment);
  138. }
  139. descriptor = FPU_get_ldt_descriptor(addr->selector);
  140. base_address = seg_get_base(&descriptor);
  141. address = base_address + offset;
  142. limit = seg_get_limit(&descriptor) + 1;
  143. limit *= seg_get_granularity(&descriptor);
  144. limit += base_address - 1;
  145. if (limit < base_address)
  146. limit = 0xffffffff;
  147. if (seg_expands_down(&descriptor)) {
  148. if (descriptor.g) {
  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_writable(&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. }