1use crate::cpu::cpu::*;
2use crate::cpu::fpu::{
3 fpu_load_m80, fpu_load_status_word, fpu_set_status_word, fpu_store_m80, set_control_word,
4};
5use crate::cpu::global_pointers::*;
6use crate::paging::OrPageFault;
7
8pub unsafe fn getcf() -> bool {
9 if 0 != *flags_changed & 1 {
10 let m = (2u32.wrapping_shl(*last_op_size as u32)).wrapping_sub(1);
11 dbg_assert!((*last_op1 as u32) <= m);
12 dbg_assert!((*last_result as u32) <= m);
13
14 let sub_mask = *flags_changed >> 31;
15
16 return ((*last_result as i32 ^ sub_mask) as u32) < (*last_op1 ^ sub_mask) as u32;
19 } else {
20 return 0 != *flags & 1;
21 };
22}
23#[no_mangle]
24pub unsafe fn getpf() -> bool {
25 if 0 != *flags_changed & FLAG_PARITY {
26 return 0 != 0x9669 << 2 >> ((*last_result ^ *last_result >> 4) & 15) & FLAG_PARITY;
28 } else {
29 return 0 != *flags & FLAG_PARITY;
30 };
31}
32pub unsafe fn getaf() -> bool {
33 if 0 != *flags_changed & FLAG_ADJUST {
34 let is_sub = *flags_changed & FLAG_SUB != 0;
35 let last_op2 = (*last_result).wrapping_sub(*last_op1) * if is_sub { -1 } else { 1 };
36 return 0 != (*last_op1 ^ last_op2 ^ *last_result) & FLAG_ADJUST;
37 } else {
38 return 0 != *flags & FLAG_ADJUST;
39 };
40}
41pub unsafe fn getzf() -> bool {
42 if 0 != *flags_changed & FLAG_ZERO {
43 return 0 != (!*last_result & (*last_result).wrapping_sub(1)) >> *last_op_size & 1;
44 } else {
45 return 0 != *flags & FLAG_ZERO;
46 };
47}
48pub unsafe fn getsf() -> bool {
49 if 0 != *flags_changed & FLAG_SIGN {
50 return 0 != *last_result >> *last_op_size & 1;
51 } else {
52 return 0 != *flags & FLAG_SIGN;
53 };
54}
55pub unsafe fn getof() -> bool {
56 if 0 != *flags_changed & FLAG_OVERFLOW {
57 let is_sub = (*flags_changed as u32) >> 31;
58
59 let b_xor_1_if_sub = (*last_result)
62 .wrapping_sub(*last_op1)
63 .wrapping_sub(is_sub as i32);
64 return 0
65 != ((*last_op1 ^ *last_result) & (b_xor_1_if_sub ^ *last_result)) >> *last_op_size & 1;
66 } else {
67 return 0 != *flags & FLAG_OVERFLOW;
68 };
69}
70
71pub unsafe fn test_o() -> bool {
72 return getof();
73}
74pub unsafe fn test_b() -> bool {
75 return getcf();
76}
77pub unsafe fn test_z() -> bool {
78 return getzf();
79}
80pub unsafe fn test_s() -> bool {
81 return getsf();
82}
83#[no_mangle]
84pub unsafe fn test_p() -> bool {
85 return getpf();
86}
87pub unsafe fn test_be() -> bool {
88 return getcf() || getzf();
89}
90pub unsafe fn test_l() -> bool {
91 return getsf() != getof();
92}
93pub unsafe fn test_le() -> bool {
94 return getzf() || getsf() != getof();
95}
96pub unsafe fn test_no() -> bool {
97 return !test_o();
98}
99pub unsafe fn test_nb() -> bool {
100 return !test_b();
101}
102pub unsafe fn test_nz() -> bool {
103 return !test_z();
104}
105pub unsafe fn test_ns() -> bool {
106 return !test_s();
107}
108#[no_mangle]
109pub unsafe fn test_np() -> bool {
110 return !test_p();
111}
112pub unsafe fn test_nbe() -> bool {
113 return !test_be();
114}
115pub unsafe fn test_nl() -> bool {
116 return !test_l();
117}
118pub unsafe fn test_nle() -> bool {
119 return !test_le();
120}
121
122pub unsafe fn jmp_rel16(rel16: i32) {
123 let cs_offset = get_seg_cs();
124 *instruction_pointer = cs_offset + (*instruction_pointer - cs_offset + rel16 & 0xFFFF);
126}
127pub unsafe fn jmpcc16(condition: bool, imm16: i32) {
128 if condition {
129 jmp_rel16(imm16);
130 };
131}
132pub unsafe fn jmpcc32(condition: bool, imm32: i32) {
133 if condition {
134 *instruction_pointer += imm32
135 };
136}
137pub unsafe fn loope16(imm8s: i32) {
138 jmpcc16(0 != decr_ecx_asize(is_asize_32()) && getzf(), imm8s);
139}
140pub unsafe fn loopne16(imm8s: i32) {
141 jmpcc16(0 != decr_ecx_asize(is_asize_32()) && !getzf(), imm8s);
142}
143pub unsafe fn loop16(imm8s: i32) {
144 jmpcc16(0 != decr_ecx_asize(is_asize_32()), imm8s);
145}
146pub unsafe fn jcxz16(imm8s: i32) {
147 jmpcc16(get_reg_asize(ECX) == 0, imm8s);
148}
149pub unsafe fn loope32(imm8s: i32) {
150 jmpcc32(0 != decr_ecx_asize(is_asize_32()) && getzf(), imm8s);
151}
152pub unsafe fn loopne32(imm8s: i32) {
153 jmpcc32(0 != decr_ecx_asize(is_asize_32()) && !getzf(), imm8s);
154}
155pub unsafe fn loop32(imm8s: i32) {
156 jmpcc32(0 != decr_ecx_asize(is_asize_32()), imm8s);
157}
158pub unsafe fn jcxz32(imm8s: i32) {
159 jmpcc32(get_reg_asize(ECX) == 0, imm8s);
160}
161
162pub unsafe fn cmovcc16(condition: bool, value: i32, r: i32) {
163 if condition {
164 write_reg16(r, value);
165 };
166}
167pub unsafe fn cmovcc32(condition: bool, value: i32, r: i32) {
168 if condition {
169 write_reg32(r, value);
170 };
171}
172
173pub unsafe fn get_stack_pointer(offset: i32) -> i32 {
174 if *stack_size_32 {
175 return get_seg_ss() + read_reg32(ESP) + offset;
176 } else {
177 return get_seg_ss() + (read_reg16(SP) + offset & 0xFFFF);
178 };
179}
180pub unsafe fn adjust_stack_reg(adjustment: i32) {
181 if *stack_size_32 {
182 write_reg32(ESP, read_reg32(ESP) + adjustment);
183 } else {
184 write_reg16(SP, read_reg16(SP) + adjustment);
185 };
186}
187
188pub unsafe fn push16_ss16(imm16: i32) -> OrPageFault<()> {
189 let sp = get_seg_ss() + (read_reg16(SP) - 2 & 0xFFFF);
190 safe_write16(sp, imm16)?;
191 write_reg16(SP, read_reg16(SP) - 2);
192 Ok(())
193}
194pub unsafe fn push16_ss32(imm16: i32) -> OrPageFault<()> {
195 let sp = get_seg_ss() + read_reg32(ESP) - 2;
196 safe_write16(sp, imm16)?;
197 write_reg32(ESP, read_reg32(ESP) - 2);
198 Ok(())
199}
200
201pub unsafe fn push16_ss16_mem(addr: i32) -> OrPageFault<()> {
202 push16_ss16(safe_read16(addr)?)
203}
204pub unsafe fn push16_ss32_mem(addr: i32) -> OrPageFault<()> {
205 push16_ss32(safe_read16(addr)?)
206}
207
208pub unsafe fn push16(imm16: i32) -> OrPageFault<()> {
209 if *stack_size_32 {
210 push16_ss32(imm16)
211 } else {
212 push16_ss16(imm16)
213 }
214}
215
216pub unsafe fn push32_ss16(imm32: i32) -> OrPageFault<()> {
217 let new_sp = read_reg16(SP) - 4 & 0xFFFF;
218 safe_write32(get_seg_ss() + new_sp, imm32)?;
219 write_reg16(SP, new_sp);
220 Ok(())
221}
222pub unsafe fn push32_ss32(imm32: i32) -> OrPageFault<()> {
223 let new_esp = read_reg32(ESP) - 4;
224 safe_write32(get_seg_ss() + new_esp, imm32)?;
225 write_reg32(ESP, new_esp);
226 Ok(())
227}
228
229pub unsafe fn push32_ss16_mem(addr: i32) -> OrPageFault<()> {
230 push32_ss16(safe_read32s(addr)?)
231}
232pub unsafe fn push32_ss32_mem(addr: i32) -> OrPageFault<()> {
233 push32_ss32(safe_read32s(addr)?)
234}
235
236pub unsafe fn push32(imm32: i32) -> OrPageFault<()> {
237 if *stack_size_32 {
238 push32_ss32(imm32)
239 } else {
240 push32_ss16(imm32)
241 }
242}
243
244pub unsafe fn push32_sreg(i: i32) -> OrPageFault<()> {
245 if *stack_size_32 {
247 let new_esp = read_reg32(ESP) - 4;
248 safe_write16(get_seg_ss() + new_esp, *sreg.offset(i as isize) as i32)?;
249 write_reg32(ESP, new_esp);
250 } else {
251 let new_sp = read_reg16(SP) - 4 & 0xFFFF;
252 safe_write16(get_seg_ss() + new_sp, *sreg.offset(i as isize) as i32)?;
253 write_reg16(SP, new_sp);
254 }
255 Ok(())
256}
257
258pub unsafe fn pop16() -> OrPageFault<i32> {
259 if *stack_size_32 {
260 pop16_ss32()
261 } else {
262 pop16_ss16()
263 }
264}
265pub unsafe fn pop16_ss16() -> OrPageFault<i32> {
266 let sp = get_seg_ss() + read_reg16(SP);
267 let result = safe_read16(sp)?;
268 write_reg16(SP, read_reg16(SP) + 2);
269 Ok(result)
270}
271pub unsafe fn pop16_ss32() -> OrPageFault<i32> {
272 let esp = get_seg_ss() + read_reg32(ESP);
273 let result = safe_read16(esp)?;
274 write_reg32(ESP, read_reg32(ESP) + 2);
275 Ok(result)
276}
277pub unsafe fn pop32s() -> OrPageFault<i32> {
278 if *stack_size_32 {
279 pop32s_ss32()
280 } else {
281 pop32s_ss16()
282 }
283}
284pub unsafe fn pop32s_ss16() -> OrPageFault<i32> {
285 let sp = read_reg16(SP);
286 let result = safe_read32s(get_seg_ss() + sp)?;
287 write_reg16(SP, sp + 4);
288 Ok(result)
289}
290pub unsafe fn pop32s_ss32() -> OrPageFault<i32> {
291 let esp = read_reg32(ESP);
292 let result = safe_read32s(get_seg_ss() + esp)?;
293 write_reg32(ESP, read_reg32(ESP) + 4);
294 Ok(result)
295}
296pub unsafe fn pusha16() {
297 let temp = read_reg16(SP);
298 return_on_pagefault!(writable_or_pagefault(get_stack_pointer(-16), 16));
301 push16(read_reg16(AX)).unwrap();
302 push16(read_reg16(CX)).unwrap();
303 push16(read_reg16(DX)).unwrap();
304 push16(read_reg16(BX)).unwrap();
305 push16(temp as i32).unwrap();
306 push16(read_reg16(BP)).unwrap();
307 push16(read_reg16(SI)).unwrap();
308 push16(read_reg16(DI)).unwrap();
309}
310pub unsafe fn pusha32() {
311 let temp = read_reg32(ESP);
312 return_on_pagefault!(writable_or_pagefault(get_stack_pointer(-32), 32));
313 push32(read_reg32(EAX)).unwrap();
314 push32(read_reg32(ECX)).unwrap();
315 push32(read_reg32(EDX)).unwrap();
316 push32(read_reg32(EBX)).unwrap();
317 push32(temp).unwrap();
318 push32(read_reg32(EBP)).unwrap();
319 push32(read_reg32(ESI)).unwrap();
320 push32(read_reg32(EDI)).unwrap();
321}
322
323pub unsafe fn lss16(addr: i32, reg: i32, seg: i32) {
324 let new_reg = return_on_pagefault!(safe_read16(addr));
325 let new_seg = return_on_pagefault!(safe_read16(addr + 2));
326
327 if !switch_seg(seg, new_seg) {
328 return;
329 }
330
331 write_reg16(reg, new_reg);
332}
333
334pub unsafe fn lss32(addr: i32, reg: i32, seg: i32) {
335 let new_reg = return_on_pagefault!(safe_read32s(addr));
336 let new_seg = return_on_pagefault!(safe_read16(addr + 4));
337
338 if !switch_seg(seg, new_seg) {
339 return;
340 }
341
342 write_reg32(reg, new_reg);
343}
344
345pub unsafe fn enter16(size: i32, mut nesting_level: i32) {
346 nesting_level &= 31;
347
348 if nesting_level > 0 {
349 dbg_log!(
350 "enter16 stack={} size={} nest={}",
351 (if *stack_size_32 { 16 } else { 32 }),
352 size,
353 nesting_level,
354 );
355 }
356
357 let ss_mask = if *stack_size_32 { -1 } else { 0xFFFF };
358 let ss = get_seg_ss();
359 let frame_temp = read_reg32(ESP) - 2;
360
361 if nesting_level > 0 {
362 let mut tmp_ebp = read_reg32(EBP);
363 for _ in 1..nesting_level {
364 tmp_ebp -= 2;
365 push16(safe_read16(ss + (tmp_ebp & ss_mask)).unwrap()).unwrap();
366 }
367 push16(frame_temp).unwrap();
368 }
369
370 return_on_pagefault!(safe_write16(ss + (frame_temp & ss_mask), read_reg16(BP)));
371 write_reg16(BP, frame_temp);
372 adjust_stack_reg(-size - 2);
373}
374
375pub unsafe fn enter32(size: i32, mut nesting_level: i32) {
376 nesting_level &= 31;
377
378 if nesting_level > 0 {
379 dbg_log!(
380 "enter32 stack={} size={} nest={}",
381 (if *stack_size_32 { 16 } else { 32 }),
382 size,
383 nesting_level,
384 );
385 }
386
387 let ss_mask = if *stack_size_32 { -1 } else { 0xFFFF };
388 let ss = get_seg_ss();
389 let frame_temp = read_reg32(ESP) - 4;
390
391 if nesting_level > 0 {
392 let mut tmp_ebp = read_reg32(EBP);
393 for _ in 1..nesting_level {
394 tmp_ebp -= 4;
395 push32(safe_read32s(ss + (tmp_ebp & ss_mask)).unwrap()).unwrap();
396 }
397 push32(frame_temp).unwrap();
398 }
399
400 return_on_pagefault!(safe_write32(ss + (frame_temp & ss_mask), read_reg32(EBP)));
401 write_reg32(EBP, frame_temp);
402 adjust_stack_reg(-size - 4);
403}
404
405pub unsafe fn setcc_reg(condition: bool, r: i32) {
406 write_reg8(r, condition as i32);
407}
408pub unsafe fn setcc_mem(condition: bool, addr: i32) {
409 return_on_pagefault!(safe_write8(addr, condition as i32));
410}
411
412pub unsafe fn fxsave(addr: i32) {
413 dbg_assert!(addr & 0xF == 0, "TODO: #gp");
414 return_on_pagefault!(writable_or_pagefault(addr, 288));
415
416 safe_write16(addr + 0, (*fpu_control_word).into()).unwrap();
417 safe_write16(addr + 2, fpu_load_status_word().into()).unwrap();
418 safe_write8(addr + 4, !*fpu_stack_empty as i32 & 0xFF).unwrap();
419 safe_write16(addr + 6, *fpu_opcode).unwrap();
420 safe_write32(addr + 8, *fpu_ip).unwrap();
421 safe_write16(addr + 12, *fpu_ip_selector).unwrap();
422 safe_write32(addr + 16, *fpu_dp).unwrap();
423 safe_write16(addr + 20, *fpu_dp_selector).unwrap();
424
425 safe_write32(addr + 24, *mxcsr).unwrap();
426 safe_write32(addr + 28, MXCSR_MASK).unwrap();
427
428 for i in 0..8 {
429 let reg_index = i + *fpu_stack_ptr as i32 & 7;
430 fpu_store_m80(addr + 32 + (i << 4), *fpu_st.offset(reg_index as isize));
431 }
432
433 for i in 0..8 {
437 safe_write128(addr + 160 + (i << 4), *reg_xmm.offset(i as isize)).unwrap();
438 }
439}
440pub unsafe fn fxrstor(addr: i32) {
441 dbg_assert!(addr & 0xF == 0, "TODO: #gp");
442 return_on_pagefault!(readable_or_pagefault(addr, 288));
443
444 let new_mxcsr = safe_read32s(addr + 24).unwrap();
445
446 if 0 != new_mxcsr & !MXCSR_MASK {
447 dbg_log!("#gp Invalid mxcsr bits");
448 trigger_gp(0);
449 return;
450 }
451
452 set_control_word(safe_read16(addr + 0).unwrap() as u16);
453 fpu_set_status_word(safe_read16(addr + 2).unwrap() as u16);
454 *fpu_stack_empty = !safe_read8(addr + 4).unwrap() as u8;
455 *fpu_opcode = safe_read16(addr + 6).unwrap();
456 *fpu_ip = safe_read32s(addr + 8).unwrap();
457 *fpu_ip_selector = safe_read16(addr + 12).unwrap();
458 *fpu_dp = safe_read32s(addr + 16).unwrap();
459 *fpu_dp_selector = safe_read16(addr + 20).unwrap();
460
461 set_mxcsr(new_mxcsr);
462
463 for i in 0..8 {
464 let reg_index = *fpu_stack_ptr as i32 + i & 7;
465 *fpu_st.offset(reg_index as isize) = fpu_load_m80(addr + 32 + (i << 4)).unwrap();
466 }
467
468 for i in 0..8 {
469 *reg_xmm.offset(i as isize) = safe_read128s(addr + 160 + (i << 4)).unwrap();
470 }
471}
472
473pub unsafe fn xchg8(data: i32, r8: i32) -> i32 {
474 let tmp = read_reg8(r8);
475 write_reg8(r8, data);
476 return tmp;
477}
478pub unsafe fn xchg16(data: i32, r16: i32) -> i32 {
479 let tmp = read_reg16(r16);
480 write_reg16(r16, data);
481 return tmp;
482}
483pub unsafe fn xchg16r(r16: i32) {
484 let tmp = read_reg16(AX);
485 write_reg16(AX, read_reg16(r16));
486 write_reg16(r16, tmp);
487}
488pub unsafe fn xchg32(data: i32, r32: i32) -> i32 {
489 let tmp = read_reg32(r32);
490 write_reg32(r32, data);
491 return tmp;
492}
493pub unsafe fn xchg32r(r32: i32) {
494 let tmp = read_reg32(EAX);
495 write_reg32(EAX, read_reg32(r32));
496 write_reg32(r32, tmp);
497}
498
499pub unsafe fn bswap(r: i32) {
500 write_reg32(r, read_reg32(r).swap_bytes())
501}
502
503pub unsafe fn lar(selector: i32, original: i32) -> i32 {
504 if false {
505 dbg_log!("lar sel={:x}", selector);
506 }
507
508 const LAR_INVALID_TYPE: u32 =
509 1 << 0 | 1 << 6 | 1 << 7 | 1 << 8 | 1 << 0xA | 1 << 0xD | 1 << 0xE | 1 << 0xF;
510
511 let sel = SegmentSelector::of_u16(selector as u16);
512 match lookup_segment_selector(sel) {
513 Err(()) => {
514 return original;
516 }
517 Ok(Err(_)) => {
518 *flags_changed &= !FLAG_ZERO;
519 *flags &= !FLAG_ZERO;
520 dbg_log!("lar: invalid selector={:x}: null or invalid", selector);
521 return original;
522 }
523 Ok(Ok((desc, _))) => {
524 *flags_changed &= !FLAG_ZERO;
525 let dpl_bad = desc.dpl() < *cpl || desc.dpl() < sel.rpl();
526
527 if if desc.is_system() {
528 (LAR_INVALID_TYPE >> desc.system_type() & 1 == 1) || dpl_bad
529 } else {
530 !desc.is_conforming_executable() && dpl_bad
531 } {
532 dbg_log!(
533 "lar: invalid selector={:x} is_null={} is_system={}",
534 selector,
535 false,
536 desc.is_system()
537 );
538 *flags &= !FLAG_ZERO;
539 return original;
540 } else {
541 *flags |= FLAG_ZERO;
542 return (desc.raw >> 32) as i32 & 0x00FFFF00;
543 }
544 }
545 }
546}
547
548pub unsafe fn lsl(selector: i32, original: i32) -> i32 {
549 if false {
550 dbg_log!("lsl sel={:x}", selector);
551 }
552
553 const LSL_INVALID_TYPE: i32 = 1 << 0
554 | 1 << 4
555 | 1 << 5
556 | 1 << 6
557 | 1 << 7
558 | 1 << 8
559 | 1 << 0xA
560 | 1 << 0xC
561 | 1 << 0xD
562 | 1 << 0xE
563 | 1 << 0xF;
564
565 let sel = SegmentSelector::of_u16(selector as u16);
566 match lookup_segment_selector(sel) {
567 Err(()) => {
568 return original;
570 }
571 Ok(Err(_)) => {
572 *flags_changed &= !FLAG_ZERO;
573 *flags &= !FLAG_ZERO;
574 dbg_log!("lsl: invalid selector={:x}: null or invalid", selector);
575 return original;
576 }
577 Ok(Ok((desc, _))) => {
578 *flags_changed &= !FLAG_ZERO;
579 let dpl_bad = desc.dpl() < *cpl || desc.dpl() < sel.rpl();
580
581 if if desc.is_system() {
582 (LSL_INVALID_TYPE >> desc.system_type() & 1 == 1) || dpl_bad
583 } else {
584 !desc.is_conforming_executable() && dpl_bad
585 } {
586 dbg_log!(
587 "lsl: invalid selector={:x} is_null={} is_system={}",
588 selector,
589 false,
590 desc.is_system(),
591 );
592 *flags &= !FLAG_ZERO;
593 return original;
594 } else {
595 *flags |= FLAG_ZERO;
596 return desc.effective_limit() as i32;
597 }
598 }
599 }
600}
601
602pub unsafe fn verr(selector: i32) {
603 *flags_changed &= !FLAG_ZERO;
604 let sel = SegmentSelector::of_u16(selector as u16);
605 match return_on_pagefault!(lookup_segment_selector(sel)) {
606 Err(_) => {
607 *flags &= !FLAG_ZERO;
608 dbg_log!("verr -> invalid. selector={:x}", selector);
609 }
610 Ok((desc, _)) => {
611 if desc.is_system()
612 || !desc.is_readable()
613 || (!desc.is_conforming_executable()
614 && (desc.dpl() < *cpl || desc.dpl() < sel.rpl()))
615 {
616 dbg_log!("verr -> invalid. selector={:x}", selector);
617 *flags &= !FLAG_ZERO;
618 } else {
619 dbg_log!("verr -> valid. selector={:x}", selector);
620 *flags |= FLAG_ZERO;
621 }
622 }
623 }
624}
625
626pub unsafe fn verw(selector: i32) {
627 *flags_changed &= !FLAG_ZERO;
628 let sel = SegmentSelector::of_u16(selector as u16);
629 match return_on_pagefault!(lookup_segment_selector(sel)) {
630 Err(_) => {
631 *flags &= !FLAG_ZERO;
632 dbg_log!("verw -> invalid. selector={:x}", selector);
633 }
634 Ok((desc, _)) => {
635 if desc.is_system()
636 || !desc.is_writable()
637 || desc.dpl() < *cpl
638 || desc.dpl() < sel.rpl()
639 {
640 dbg_log!(
641 "verw invalid selector={:x} is_system={} is_writable={}",
642 selector,
643 desc.is_system(),
644 desc.is_writable(),
645 );
646 *flags &= !FLAG_ZERO;
647 } else {
648 *flags |= FLAG_ZERO;
649 }
650 }
651 }
652}