aboutsummaryrefslogtreecommitdiff
path: root/target-i386/seg_helper.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2014-03-28 18:47:57 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2014-06-05 16:10:34 +0200
commit81cf8d8adc64203567e03326c13ea4abec9fe5df (patch)
treee84fe22b7f5a14a85bf9e3a8b8736d07ba89024d /target-i386/seg_helper.c
parent43773ed369a2e1f6c347e30c74df27a8750d1d2d (diff)
target-i386: move check_io helpers to seg_helper.c
Prepare for adding _kernel accessors there in the next patch. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target-i386/seg_helper.c')
-rw-r--r--target-i386/seg_helper.c42
1 files changed, 42 insertions, 0 deletions
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index ba472154e8..31c5508e6c 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -2469,3 +2469,45 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector)
}
}
#endif
+
+/* check if Port I/O is allowed in TSS */
+static inline void check_io(CPUX86State *env, int addr, int size)
+{
+ int io_offset, val, mask;
+
+ /* TSS must be a valid 32 bit one */
+ if (!(env->tr.flags & DESC_P_MASK) ||
+ ((env->tr.flags >> DESC_TYPE_SHIFT) & 0xf) != 9 ||
+ env->tr.limit < 103) {
+ goto fail;
+ }
+ io_offset = cpu_lduw_kernel(env, env->tr.base + 0x66);
+ io_offset += (addr >> 3);
+ /* Note: the check needs two bytes */
+ if ((io_offset + 1) > env->tr.limit) {
+ goto fail;
+ }
+ val = cpu_lduw_kernel(env, env->tr.base + io_offset);
+ val >>= (addr & 7);
+ mask = (1 << size) - 1;
+ /* all bits must be zero to allow the I/O */
+ if ((val & mask) != 0) {
+ fail:
+ raise_exception_err(env, EXCP0D_GPF, 0);
+ }
+}
+
+void helper_check_iob(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 1);
+}
+
+void helper_check_iow(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 2);
+}
+
+void helper_check_iol(CPUX86State *env, uint32_t t0)
+{
+ check_io(env, t0, 4);
+}