| 549 | } |
| 550 | |
| 551 | void CPU::ret(U32 big, U32 bytes) { |
| 552 | if (this->flags & VM) { |
| 553 | U32 new_ip = 0; |
| 554 | U32 new_cs = 0; |
| 555 | if (big) { |
| 556 | new_ip = pop32(); |
| 557 | new_cs = pop32() & 0xffff; |
| 558 | } else { |
| 559 | new_ip = pop16(); |
| 560 | new_cs = pop16(); |
| 561 | } |
| 562 | THIS_ESP = (THIS_ESP & this->stackNotMask) | ((THIS_ESP + bytes ) & this->stackMask); |
| 563 | this->setSegment(CS, new_cs); |
| 564 | this->eip.u32 = new_ip; |
| 565 | this->setIsBig(0); |
| 566 | } else { |
| 567 | U32 selector = 0; |
| 568 | |
| 569 | if (big) |
| 570 | selector = peek32(1); |
| 571 | else |
| 572 | selector = peek16(1); |
| 573 | |
| 574 | U32 rpl=selector & 3; // requested privilege level |
| 575 | if(rpl < this->cpl) { |
| 576 | this->prepareException(EXCEPTION_GP, selector & 0xfffc); |
| 577 | return; |
| 578 | } |
| 579 | U32 index = selector >> 3; |
| 580 | |
| 581 | if (CPU_CHECK_COND(this, (selector & 0xfffc)==0, "RET:CS selector zero", EXCEPTION_GP,0)) |
| 582 | return; |
| 583 | |
| 584 | if (index>=LDT_ENTRIES) { |
| 585 | CPU_CHECK_COND(this, 0, "RET:CS beyond limits", EXCEPTION_GP,selector & 0xfffc); |
| 586 | return; |
| 587 | } |
| 588 | struct user_desc* ldt = this->thread->getLDT(index); |
| 589 | if (this->thread->isLdtEmpty(ldt)) { |
| 590 | this->prepareException(EXCEPTION_NP, selector & 0xfffc); |
| 591 | return; |
| 592 | } |
| 593 | if (this->cpl==rpl) { |
| 594 | // Return to same level |
| 595 | U32 offset = 0; |
| 596 | if (big) { |
| 597 | offset = pop32(); |
| 598 | selector = pop32() & 0xffff; |
| 599 | } else { |
| 600 | offset = pop16(); |
| 601 | selector = pop16(); |
| 602 | } |
| 603 | this->setSeg(CS, ldt->base_addr, selector); |
| 604 | this->setIsBig(ldt->seg_32bit); |
| 605 | this->eip.u32 = offset; |
| 606 | THIS_ESP = (THIS_ESP & this->stackNotMask) | ((THIS_ESP + bytes ) & this->stackMask); |
| 607 | } else { |
| 608 | // Return to outer level |
no test coverage detected