Explorar o código

dyncom: Handle unprivileged load/store variants correctly

LDRT/LDRBT/STRBT/STRT should simulate the load or store
as if the host CPU is in user mode.

STRT is also allowed to use the PC as an operand
Lioncash %!s(int64=10) %!d(string=hai) anos
pai
achega
5a531d7ec2
Modificáronse 1 ficheiros con 33 adicións e 7 borrados
  1. 33 7
      src/core/arm/dyncom/arm_dyncom_interpreter.cpp

+ 33 - 7
src/core/arm/dyncom/arm_dyncom_interpreter.cpp

@@ -4494,9 +4494,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
 
 
-            cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory8(addr);
+            const u32 dest_index = BITS(inst_cream->inst, 12, 15);
+            const u32 previous_mode = cpu->Mode;
 
 
-            if (BITS(inst_cream->inst, 12, 15) == 15) {
+            cpu->ChangePrivilegeMode(USER32MODE);
+            const u8 value = cpu->ReadMemory8(addr);
+            cpu->ChangePrivilegeMode(previous_mode);
+
+            cpu->Reg[dest_index] = value;
+
+            if (dest_index == 15) {
                 INC_PC(sizeof(ldst_inst));
                 INC_PC(sizeof(ldst_inst));
                 goto DISPATCH;
                 goto DISPATCH;
             }
             }
@@ -4668,10 +4675,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
 
 
-            unsigned int value = cpu->ReadMemory32(addr);
-            cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
+            const u32 dest_index = BITS(inst_cream->inst, 12, 15);
+            const u32 previous_mode = cpu->Mode;
 
 
-            if (BITS(inst_cream->inst, 12, 15) == 15) {
+            cpu->ChangePrivilegeMode(USER32MODE);
+            const u32 value = cpu->ReadMemory32(addr);
+            cpu->ChangePrivilegeMode(previous_mode);
+
+            cpu->Reg[dest_index] = value;
+
+            if (dest_index == 15) {
                 INC_PC(sizeof(ldst_inst));
                 INC_PC(sizeof(ldst_inst));
                 goto DISPATCH;
                 goto DISPATCH;
             }
             }
@@ -6061,8 +6074,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
         if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
         if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
-            unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
+
+            const u32 previous_mode = cpu->Mode;
+            const u32 value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
+
+            cpu->ChangePrivilegeMode(USER32MODE);
             cpu->WriteMemory8(addr, value);
             cpu->WriteMemory8(addr, value);
+            cpu->ChangePrivilegeMode(previous_mode);
         }
         }
         cpu->Reg[15] += cpu->GetInstructionSize();
         cpu->Reg[15] += cpu->GetInstructionSize();
         INC_PC(sizeof(ldst_inst));
         INC_PC(sizeof(ldst_inst));
@@ -6196,8 +6214,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
             inst_cream->get_addr(cpu, inst_cream->inst, addr);
 
 
-            unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
+            const u32 previous_mode = cpu->Mode;
+            const u32 rt_index = BITS(inst_cream->inst, 12, 15);
+
+            u32 value = cpu->Reg[rt_index];
+            if (rt_index == 15)
+                value += 2 * cpu->GetInstructionSize();
+
+            cpu->ChangePrivilegeMode(USER32MODE);
             cpu->WriteMemory32(addr, value);
             cpu->WriteMemory32(addr, value);
+            cpu->ChangePrivilegeMode(previous_mode);
         }
         }
         cpu->Reg[15] += cpu->GetInstructionSize();
         cpu->Reg[15] += cpu->GetInstructionSize();
         INC_PC(sizeof(ldst_inst));
         INC_PC(sizeof(ldst_inst));