aboutsummaryrefslogtreecommitdiff
path: root/target/i386/tcg
diff options
context:
space:
mode:
authorGareth Webb <gareth.webb@umbralsoftware.co.uk>2022-02-19 18:15:56 +0000
committerPaolo Bonzini <pbonzini@redhat.com>2022-03-15 11:50:15 +0100
commit50fcc7cbb67213621bbe69eafff5e4625f418b4c (patch)
tree8694ecb5323900812d09957faf70dabd6a638792 /target/i386/tcg
parent991ec97625e1281ba22bd81426a7226a76baf60a (diff)
target/i386: Throw a #SS when loading a non-canonical IST
Loading a non-canonical address into rsp when handling an interrupt or performing a far call should raise a #SS not a #GP. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/870 Signed-off-by: Gareth Webb <gareth.webb@umbralsoftware.co.uk> Message-Id: <164529651121.25406.15337137068584246397-0@git.sr.ht> [Move get_pg_mode to seg_helper.c for user-mode emulators. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386/tcg')
-rw-r--r--target/i386/tcg/seg_helper.c52
-rw-r--r--target/i386/tcg/sysemu/excp_helper.c36
2 files changed, 50 insertions, 38 deletions
diff --git a/target/i386/tcg/seg_helper.c b/target/i386/tcg/seg_helper.c
index baa905a0cd..bffd82923f 100644
--- a/target/i386/tcg/seg_helper.c
+++ b/target/i386/tcg/seg_helper.c
@@ -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 */
diff --git a/target/i386/tcg/sysemu/excp_helper.c b/target/i386/tcg/sysemu/excp_helper.c
index 6f1fbe667b..e1b6d88683 100644
--- a/target/i386/tcg/sysemu/excp_helper.c
+++ b/target/i386/tcg/sysemu/excp_helper.c
@@ -22,42 +22,6 @@
#include "exec/exec-all.h"
#include "tcg/helper-tcg.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;
-}
-
#define PG_ERROR_OK (-1)
typedef hwaddr (*MMUTranslateFunc)(CPUState *cs, hwaddr gphys, MMUAccessType access_type,