|
@@ -28,6 +28,42 @@
|
|
|
#include "helper-tcg.h"
|
|
|
#include "seg_helper.h"
|
|
|
|
|
|
+int get_pg_mode(CPUX86State *env)
|
|
|
+{
|
|
|
+ int pg_mode = 0;
|
|
|
+ if (!(env->cr[0] & CR0_PG_MASK)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ if (env->cr[0] & CR0_WP_MASK) {
|
|
|
+ pg_mode |= PG_MODE_WP;
|
|
|
+ }
|
|
|
+ if (env->cr[4] & CR4_PAE_MASK) {
|
|
|
+ pg_mode |= PG_MODE_PAE;
|
|
|
+ if (env->efer & MSR_EFER_NXE) {
|
|
|
+ pg_mode |= PG_MODE_NXE;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (env->cr[4] & CR4_PSE_MASK) {
|
|
|
+ pg_mode |= PG_MODE_PSE;
|
|
|
+ }
|
|
|
+ if (env->cr[4] & CR4_SMEP_MASK) {
|
|
|
+ pg_mode |= PG_MODE_SMEP;
|
|
|
+ }
|
|
|
+ if (env->hflags & HF_LMA_MASK) {
|
|
|
+ pg_mode |= PG_MODE_LMA;
|
|
|
+ if (env->cr[4] & CR4_PKE_MASK) {
|
|
|
+ pg_mode |= PG_MODE_PKE;
|
|
|
+ }
|
|
|
+ if (env->cr[4] & CR4_PKS_MASK) {
|
|
|
+ pg_mode |= PG_MODE_PKS;
|
|
|
+ }
|
|
|
+ if (env->cr[4] & CR4_LA57_MASK) {
|
|
|
+ pg_mode |= PG_MODE_LA57;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return pg_mode;
|
|
|
+}
|
|
|
+
|
|
|
/* return non zero if error */
|
|
|
static inline int load_segment_ra(CPUX86State *env, uint32_t *e1_ptr,
|
|
|
uint32_t *e2_ptr, int selector,
|
|
@@ -794,7 +830,9 @@ static void do_interrupt_protected(CPUX86State *env, int intno, int is_int,
|
|
|
static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
|
|
|
{
|
|
|
X86CPU *cpu = env_archcpu(env);
|
|
|
- int index;
|
|
|
+ int index, pg_mode;
|
|
|
+ target_ulong rsp;
|
|
|
+ int32_t sext;
|
|
|
|
|
|
#if 0
|
|
|
printf("TR: base=" TARGET_FMT_lx " limit=%x\n",
|
|
@@ -808,7 +846,17 @@ static inline target_ulong get_rsp_from_tss(CPUX86State *env, int level)
|
|
|
if ((index + 7) > env->tr.limit) {
|
|
|
raise_exception_err(env, EXCP0A_TSS, env->tr.selector & 0xfffc);
|
|
|
}
|
|
|
- return cpu_ldq_kernel(env, env->tr.base + index);
|
|
|
+
|
|
|
+ rsp = cpu_ldq_kernel(env, env->tr.base + index);
|
|
|
+
|
|
|
+ /* test virtual address sign extension */
|
|
|
+ pg_mode = get_pg_mode(env);
|
|
|
+ sext = (int64_t)rsp >> (pg_mode & PG_MODE_LA57 ? 56 : 47);
|
|
|
+ if (sext != 0 && sext != -1) {
|
|
|
+ raise_exception_err(env, EXCP0C_STACK, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ return rsp;
|
|
|
}
|
|
|
|
|
|
/* 64 bit interrupt */
|