summaryrefslogtreecommitdiff
path: root/target/i386/tcg
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-05-14 10:13:00 -0500
committerRichard Henderson <richard.henderson@linaro.org>2021-05-19 12:15:46 -0500
commit0ab011cca08651349172187d574e2fb1316283ef (patch)
tree987b118d17247502e9412c97e442d442d27636bc /target/i386/tcg
parent01b9d8c1b23b6e5af631cb56b86011466b52789a (diff)
downloadqemu-0ab011cca08651349172187d574e2fb1316283ef.zip
target/i386: Assert IOPL is 0 for user-only
On real hardware, the linux kernel has the iopl(2) syscall which can set IOPL to 3, to allow e.g. the xserver to briefly disable interrupts while programming the graphics card. However, QEMU cannot and does not implement this syscall, so the IOPL is never changed from 0. Which means that all of the checks vs CPL <= IOPL are false for user-only. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20210514151342.384376-9-richard.henderson@linaro.org>
Diffstat (limited to 'target/i386/tcg')
-rw-r--r--target/i386/tcg/translate.c16
1 files changed, 10 insertions, 6 deletions
diff --git a/target/i386/tcg/translate.c b/target/i386/tcg/translate.c
index 4c9194416d..b8cb7163ee 100644
--- a/target/i386/tcg/translate.c
+++ b/target/i386/tcg/translate.c
@@ -97,6 +97,7 @@ typedef struct DisasContext {
#ifndef CONFIG_USER_ONLY
uint8_t cpl; /* code priv level */
+ uint8_t iopl; /* i/o priv level */
#endif
int code32; /* 32 bit code segment */
@@ -116,7 +117,6 @@ typedef struct DisasContext {
int addseg; /* non zero if either DS/ES/SS have a non zero base */
int f_st; /* currently unused */
int vm86; /* vm86 mode */
- int iopl;
int tf; /* TF cpu flag */
int jmp_opt; /* use direct block chaining for direct jumps */
int repz_opt; /* optimize jumps within repz instructions */
@@ -153,9 +153,11 @@ typedef struct DisasContext {
#ifdef CONFIG_USER_ONLY
#define PE(S) true
#define CPL(S) 3
+#define IOPL(S) 0
#else
#define PE(S) (((S)->flags & HF_PE_MASK) != 0)
#define CPL(S) ((S)->cpl)
+#define IOPL(S) ((S)->iopl)
#endif
static void gen_eob(DisasContext *s);
@@ -629,7 +631,7 @@ static void gen_check_io(DisasContext *s, MemOp ot, target_ulong cur_eip,
{
target_ulong next_eip;
- if (PE(s) && (CPL(s) > s->iopl || s->vm86)) {
+ if (PE(s) && (CPL(s) > IOPL(s) || s->vm86)) {
tcg_gen_trunc_tl_i32(s->tmp2_i32, s->T0);
switch (ot) {
case MO_8:
@@ -1307,7 +1309,7 @@ static bool check_cpl0(DisasContext *s)
/* If vm86, check for iopl == 3; if not, raise #GP and return false. */
static bool check_vm86_iopl(DisasContext *s)
{
- if (!s->vm86 || s->iopl == 3) {
+ if (!s->vm86 || IOPL(s) == 3) {
return true;
}
gen_exception_gpf(s);
@@ -1317,7 +1319,7 @@ static bool check_vm86_iopl(DisasContext *s)
/* Check for iopl allowing access; if not, raise #GP and return false. */
static bool check_iopl(DisasContext *s)
{
- if (s->vm86 ? s->iopl == 3 : CPL(s) <= s->iopl) {
+ if (s->vm86 ? IOPL(s) == 3 : CPL(s) <= IOPL(s)) {
return true;
}
gen_exception_gpf(s);
@@ -6756,7 +6758,7 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
& 0xffff));
}
} else {
- if (CPL(s) <= s->iopl) {
+ if (CPL(s) <= IOPL(s)) {
if (dflag != MO_16) {
gen_helper_write_eflags(cpu_env, s->T0,
tcg_const_i32((TF_MASK |
@@ -8474,23 +8476,25 @@ static void i386_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cpu)
CPUX86State *env = cpu->env_ptr;
uint32_t flags = dc->base.tb->flags;
int cpl = (flags >> HF_CPL_SHIFT) & 3;
+ int iopl = (flags >> IOPL_SHIFT) & 3;
dc->cs_base = dc->base.tb->cs_base;
dc->flags = flags;
#ifndef CONFIG_USER_ONLY
dc->cpl = cpl;
+ dc->iopl = iopl;
#endif
/* We make some simplifying assumptions; validate they're correct. */
g_assert(PE(dc) == ((flags & HF_PE_MASK) != 0));
g_assert(CPL(dc) == cpl);
+ g_assert(IOPL(dc) == iopl);
dc->code32 = (flags >> HF_CS32_SHIFT) & 1;
dc->ss32 = (flags >> HF_SS32_SHIFT) & 1;
dc->addseg = (flags >> HF_ADDSEG_SHIFT) & 1;
dc->f_st = 0;
dc->vm86 = (flags >> VM_SHIFT) & 1;
- dc->iopl = (flags >> IOPL_SHIFT) & 3;
dc->tf = (flags >> TF_SHIFT) & 1;
dc->cc_op = CC_OP_DYNAMIC;
dc->cc_op_dirty = false;