target/i386/tcg: save current task state before loading new one
This is how the steps are ordered in the manual. EFLAGS.NT is overwritten after the fact in the saved image. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									8b13106508
								
							
						
					
					
						commit
						6a079f2e68
					
				| @ -389,6 +389,42 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector, | |||||||
|     access_prepare_mmu(&new, env, tss_base, tss_limit, |     access_prepare_mmu(&new, env, tss_base, tss_limit, | ||||||
|                        MMU_DATA_LOAD, mmu_index, retaddr); |                        MMU_DATA_LOAD, mmu_index, retaddr); | ||||||
| 
 | 
 | ||||||
|  |     /* save the current state in the old TSS */ | ||||||
|  |     old_eflags = cpu_compute_eflags(env); | ||||||
|  |     if (old_type & 8) { | ||||||
|  |         /* 32 bit */ | ||||||
|  |         access_stl(&old, env->tr.base + 0x20, next_eip); | ||||||
|  |         access_stl(&old, env->tr.base + 0x24, old_eflags); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI]); | ||||||
|  |         access_stl(&old, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI]); | ||||||
|  |         for (i = 0; i < 6; i++) { | ||||||
|  |             access_stw(&old, env->tr.base + (0x48 + i * 4), | ||||||
|  |                        env->segs[i].selector); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         /* 16 bit */ | ||||||
|  |         access_stw(&old, env->tr.base + 0x0e, next_eip); | ||||||
|  |         access_stw(&old, env->tr.base + 0x10, old_eflags); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI]); | ||||||
|  |         access_stw(&old, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI]); | ||||||
|  |         for (i = 0; i < 4; i++) { | ||||||
|  |             access_stw(&old, env->tr.base + (0x22 + i * 2), | ||||||
|  |                        env->segs[i].selector); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* read all the registers from the new TSS */ |     /* read all the registers from the new TSS */ | ||||||
|     if (type & 8) { |     if (type & 8) { | ||||||
|         /* 32 bit */ |         /* 32 bit */ | ||||||
| @ -428,49 +464,16 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector, | |||||||
|     if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { |     if (source == SWITCH_TSS_JMP || source == SWITCH_TSS_IRET) { | ||||||
|         tss_set_busy(env, env->tr.selector, 0, retaddr); |         tss_set_busy(env, env->tr.selector, 0, retaddr); | ||||||
|     } |     } | ||||||
|     old_eflags = cpu_compute_eflags(env); | 
 | ||||||
|     if (source == SWITCH_TSS_IRET) { |     if (source == SWITCH_TSS_IRET) { | ||||||
|         old_eflags &= ~NT_MASK; |         old_eflags &= ~NT_MASK; | ||||||
|  |         if (old_type & 8) { | ||||||
|  |             access_stl(&old, env->tr.base + 0x24, old_eflags); | ||||||
|  |         } else { | ||||||
|  |             access_stw(&old, env->tr.base + 0x10, old_eflags); | ||||||
|  | 	} | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* save the current state in the old TSS */ |  | ||||||
|     if (old_type & 8) { |  | ||||||
|         /* 32 bit */ |  | ||||||
|         access_stl(&old, env->tr.base + 0x20, next_eip); |  | ||||||
|         access_stl(&old, env->tr.base + 0x24, old_eflags); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 0 * 4), env->regs[R_EAX]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 1 * 4), env->regs[R_ECX]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 2 * 4), env->regs[R_EDX]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 3 * 4), env->regs[R_EBX]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 4 * 4), env->regs[R_ESP]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 5 * 4), env->regs[R_EBP]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 6 * 4), env->regs[R_ESI]); |  | ||||||
|         access_stl(&old, env->tr.base + (0x28 + 7 * 4), env->regs[R_EDI]); |  | ||||||
|         for (i = 0; i < 6; i++) { |  | ||||||
|             access_stw(&old, env->tr.base + (0x48 + i * 4), |  | ||||||
|                        env->segs[i].selector); |  | ||||||
|         } |  | ||||||
|     } else { |  | ||||||
|         /* 16 bit */ |  | ||||||
|         access_stw(&old, env->tr.base + 0x0e, next_eip); |  | ||||||
|         access_stw(&old, env->tr.base + 0x10, old_eflags); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 0 * 2), env->regs[R_EAX]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 1 * 2), env->regs[R_ECX]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 2 * 2), env->regs[R_EDX]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 3 * 2), env->regs[R_EBX]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 4 * 2), env->regs[R_ESP]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 5 * 2), env->regs[R_EBP]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 6 * 2), env->regs[R_ESI]); |  | ||||||
|         access_stw(&old, env->tr.base + (0x12 + 7 * 2), env->regs[R_EDI]); |  | ||||||
|         for (i = 0; i < 4; i++) { |  | ||||||
|             access_stw(&old, env->tr.base + (0x22 + i * 2), |  | ||||||
|                        env->segs[i].selector); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /* now if an exception occurs, it will occurs in the next task
 |  | ||||||
|        context */ |  | ||||||
| 
 |  | ||||||
|     if (source == SWITCH_TSS_CALL) { |     if (source == SWITCH_TSS_CALL) { | ||||||
|         /*
 |         /*
 | ||||||
|          * Thanks to the probe_access above, we know the first two |          * Thanks to the probe_access above, we know the first two | ||||||
| @ -486,7 +489,9 @@ static int switch_tss_ra(CPUX86State *env, int tss_selector, | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* set the new CPU state */ |     /* set the new CPU state */ | ||||||
|     /* from this point, any exception which occurs can give problems */ | 
 | ||||||
|  |     /* now if an exception occurs, it will occur in the next task context */ | ||||||
|  | 
 | ||||||
|     env->cr[0] |= CR0_TS_MASK; |     env->cr[0] |= CR0_TS_MASK; | ||||||
|     env->hflags |= HF_TS_MASK; |     env->hflags |= HF_TS_MASK; | ||||||
|     env->tr.selector = tss_selector; |     env->tr.selector = tss_selector; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini