diff options
author | Avi Kivity <avi@redhat.com> | 2010-11-22 10:53:22 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-01-12 04:29:54 -0500 |
commit | bcc55cba9f1fcda68412c8c3d8579c56d90b16f2 (patch) | |
tree | 1f4c45ad993e66effaaf2aa0bc7d2ebade6c41d0 /arch/x86/kvm/emulate.c | |
parent | da9cb575b1127f84984b8ad6d973dcc05ac036dd (diff) |
KVM: x86 emulator: make emulator memory callbacks return full exception
This way, they can return #GP, not just #PF.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 89 |
1 files changed, 31 insertions, 58 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 18596e6649aa..16ed6c178bb2 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -512,7 +512,7 @@ static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, | |||
512 | cur_size = fc->end - fc->start; | 512 | cur_size = fc->end - fc->start; |
513 | size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip)); | 513 | size = min(15UL - cur_size, PAGE_SIZE - offset_in_page(eip)); |
514 | rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size, | 514 | rc = ops->fetch(ctxt->cs_base + eip, fc->data + cur_size, |
515 | size, ctxt->vcpu, NULL); | 515 | size, ctxt->vcpu, &ctxt->exception); |
516 | if (rc != X86EMUL_CONTINUE) | 516 | if (rc != X86EMUL_CONTINUE) |
517 | return rc; | 517 | return rc; |
518 | fc->end += size; | 518 | fc->end += size; |
@@ -565,12 +565,12 @@ static int read_descriptor(struct x86_emulate_ctxt *ctxt, | |||
565 | op_bytes = 3; | 565 | op_bytes = 3; |
566 | *address = 0; | 566 | *address = 0; |
567 | rc = ops->read_std(linear(ctxt, addr), (unsigned long *)size, 2, | 567 | rc = ops->read_std(linear(ctxt, addr), (unsigned long *)size, 2, |
568 | ctxt->vcpu, NULL); | 568 | ctxt->vcpu, &ctxt->exception); |
569 | if (rc != X86EMUL_CONTINUE) | 569 | if (rc != X86EMUL_CONTINUE) |
570 | return rc; | 570 | return rc; |
571 | addr.ea += 2; | 571 | addr.ea += 2; |
572 | rc = ops->read_std(linear(ctxt, addr), address, op_bytes, | 572 | rc = ops->read_std(linear(ctxt, addr), address, op_bytes, |
573 | ctxt->vcpu, NULL); | 573 | ctxt->vcpu, &ctxt->exception); |
574 | return rc; | 574 | return rc; |
575 | } | 575 | } |
576 | 576 | ||
@@ -816,7 +816,6 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, | |||
816 | { | 816 | { |
817 | int rc; | 817 | int rc; |
818 | struct read_cache *mc = &ctxt->decode.mem_read; | 818 | struct read_cache *mc = &ctxt->decode.mem_read; |
819 | u32 err; | ||
820 | 819 | ||
821 | while (size) { | 820 | while (size) { |
822 | int n = min(size, 8u); | 821 | int n = min(size, 8u); |
@@ -824,10 +823,8 @@ static int read_emulated(struct x86_emulate_ctxt *ctxt, | |||
824 | if (mc->pos < mc->end) | 823 | if (mc->pos < mc->end) |
825 | goto read_cached; | 824 | goto read_cached; |
826 | 825 | ||
827 | rc = ops->read_emulated(addr, mc->data + mc->end, n, &err, | 826 | rc = ops->read_emulated(addr, mc->data + mc->end, n, |
828 | ctxt->vcpu); | 827 | &ctxt->exception, ctxt->vcpu); |
829 | if (rc == X86EMUL_PROPAGATE_FAULT) | ||
830 | emulate_pf(ctxt); | ||
831 | if (rc != X86EMUL_CONTINUE) | 828 | if (rc != X86EMUL_CONTINUE) |
832 | return rc; | 829 | return rc; |
833 | mc->end += n; | 830 | mc->end += n; |
@@ -902,7 +899,6 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
902 | struct desc_ptr dt; | 899 | struct desc_ptr dt; |
903 | u16 index = selector >> 3; | 900 | u16 index = selector >> 3; |
904 | int ret; | 901 | int ret; |
905 | u32 err; | ||
906 | ulong addr; | 902 | ulong addr; |
907 | 903 | ||
908 | get_descriptor_table_ptr(ctxt, ops, selector, &dt); | 904 | get_descriptor_table_ptr(ctxt, ops, selector, &dt); |
@@ -912,9 +908,8 @@ static int read_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
912 | return X86EMUL_PROPAGATE_FAULT; | 908 | return X86EMUL_PROPAGATE_FAULT; |
913 | } | 909 | } |
914 | addr = dt.address + index * 8; | 910 | addr = dt.address + index * 8; |
915 | ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, &err); | 911 | ret = ops->read_std(addr, desc, sizeof *desc, ctxt->vcpu, |
916 | if (ret == X86EMUL_PROPAGATE_FAULT) | 912 | &ctxt->exception); |
917 | emulate_pf(ctxt); | ||
918 | 913 | ||
919 | return ret; | 914 | return ret; |
920 | } | 915 | } |
@@ -926,7 +921,6 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
926 | { | 921 | { |
927 | struct desc_ptr dt; | 922 | struct desc_ptr dt; |
928 | u16 index = selector >> 3; | 923 | u16 index = selector >> 3; |
929 | u32 err; | ||
930 | ulong addr; | 924 | ulong addr; |
931 | int ret; | 925 | int ret; |
932 | 926 | ||
@@ -938,9 +932,8 @@ static int write_segment_descriptor(struct x86_emulate_ctxt *ctxt, | |||
938 | } | 932 | } |
939 | 933 | ||
940 | addr = dt.address + index * 8; | 934 | addr = dt.address + index * 8; |
941 | ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, &err); | 935 | ret = ops->write_std(addr, desc, sizeof *desc, ctxt->vcpu, |
942 | if (ret == X86EMUL_PROPAGATE_FAULT) | 936 | &ctxt->exception); |
943 | emulate_pf(ctxt); | ||
944 | 937 | ||
945 | return ret; | 938 | return ret; |
946 | } | 939 | } |
@@ -1087,7 +1080,6 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, | |||
1087 | { | 1080 | { |
1088 | int rc; | 1081 | int rc; |
1089 | struct decode_cache *c = &ctxt->decode; | 1082 | struct decode_cache *c = &ctxt->decode; |
1090 | u32 err; | ||
1091 | 1083 | ||
1092 | switch (c->dst.type) { | 1084 | switch (c->dst.type) { |
1093 | case OP_REG: | 1085 | case OP_REG: |
@@ -1100,17 +1092,15 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, | |||
1100 | &c->dst.orig_val, | 1092 | &c->dst.orig_val, |
1101 | &c->dst.val, | 1093 | &c->dst.val, |
1102 | c->dst.bytes, | 1094 | c->dst.bytes, |
1103 | &err, | 1095 | &ctxt->exception, |
1104 | ctxt->vcpu); | 1096 | ctxt->vcpu); |
1105 | else | 1097 | else |
1106 | rc = ops->write_emulated( | 1098 | rc = ops->write_emulated( |
1107 | linear(ctxt, c->dst.addr.mem), | 1099 | linear(ctxt, c->dst.addr.mem), |
1108 | &c->dst.val, | 1100 | &c->dst.val, |
1109 | c->dst.bytes, | 1101 | c->dst.bytes, |
1110 | &err, | 1102 | &ctxt->exception, |
1111 | ctxt->vcpu); | 1103 | ctxt->vcpu); |
1112 | if (rc == X86EMUL_PROPAGATE_FAULT) | ||
1113 | emulate_pf(ctxt); | ||
1114 | if (rc != X86EMUL_CONTINUE) | 1104 | if (rc != X86EMUL_CONTINUE) |
1115 | return rc; | 1105 | return rc; |
1116 | break; | 1106 | break; |
@@ -1283,7 +1273,6 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, | |||
1283 | gva_t cs_addr; | 1273 | gva_t cs_addr; |
1284 | gva_t eip_addr; | 1274 | gva_t eip_addr; |
1285 | u16 cs, eip; | 1275 | u16 cs, eip; |
1286 | u32 err; | ||
1287 | 1276 | ||
1288 | /* TODO: Add limit checks */ | 1277 | /* TODO: Add limit checks */ |
1289 | c->src.val = ctxt->eflags; | 1278 | c->src.val = ctxt->eflags; |
@@ -1313,11 +1302,11 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, | |||
1313 | eip_addr = dt.address + (irq << 2); | 1302 | eip_addr = dt.address + (irq << 2); |
1314 | cs_addr = dt.address + (irq << 2) + 2; | 1303 | cs_addr = dt.address + (irq << 2) + 2; |
1315 | 1304 | ||
1316 | rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &err); | 1305 | rc = ops->read_std(cs_addr, &cs, 2, ctxt->vcpu, &ctxt->exception); |
1317 | if (rc != X86EMUL_CONTINUE) | 1306 | if (rc != X86EMUL_CONTINUE) |
1318 | return rc; | 1307 | return rc; |
1319 | 1308 | ||
1320 | rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &err); | 1309 | rc = ops->read_std(eip_addr, &eip, 2, ctxt->vcpu, &ctxt->exception); |
1321 | if (rc != X86EMUL_CONTINUE) | 1310 | if (rc != X86EMUL_CONTINUE) |
1322 | return rc; | 1311 | return rc; |
1323 | 1312 | ||
@@ -1930,33 +1919,27 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, | |||
1930 | { | 1919 | { |
1931 | struct tss_segment_16 tss_seg; | 1920 | struct tss_segment_16 tss_seg; |
1932 | int ret; | 1921 | int ret; |
1933 | u32 err, new_tss_base = get_desc_base(new_desc); | 1922 | u32 new_tss_base = get_desc_base(new_desc); |
1934 | 1923 | ||
1935 | ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 1924 | ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
1936 | &err); | 1925 | &ctxt->exception); |
1937 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 1926 | if (ret == X86EMUL_PROPAGATE_FAULT) |
1938 | /* FIXME: need to provide precise fault address */ | 1927 | /* FIXME: need to provide precise fault address */ |
1939 | emulate_pf(ctxt); | ||
1940 | return ret; | 1928 | return ret; |
1941 | } | ||
1942 | 1929 | ||
1943 | save_state_to_tss16(ctxt, ops, &tss_seg); | 1930 | save_state_to_tss16(ctxt, ops, &tss_seg); |
1944 | 1931 | ||
1945 | ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 1932 | ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
1946 | &err); | 1933 | &ctxt->exception); |
1947 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 1934 | if (ret == X86EMUL_PROPAGATE_FAULT) |
1948 | /* FIXME: need to provide precise fault address */ | 1935 | /* FIXME: need to provide precise fault address */ |
1949 | emulate_pf(ctxt); | ||
1950 | return ret; | 1936 | return ret; |
1951 | } | ||
1952 | 1937 | ||
1953 | ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 1938 | ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
1954 | &err); | 1939 | &ctxt->exception); |
1955 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 1940 | if (ret == X86EMUL_PROPAGATE_FAULT) |
1956 | /* FIXME: need to provide precise fault address */ | 1941 | /* FIXME: need to provide precise fault address */ |
1957 | emulate_pf(ctxt); | ||
1958 | return ret; | 1942 | return ret; |
1959 | } | ||
1960 | 1943 | ||
1961 | if (old_tss_sel != 0xffff) { | 1944 | if (old_tss_sel != 0xffff) { |
1962 | tss_seg.prev_task_link = old_tss_sel; | 1945 | tss_seg.prev_task_link = old_tss_sel; |
@@ -1964,12 +1947,10 @@ static int task_switch_16(struct x86_emulate_ctxt *ctxt, | |||
1964 | ret = ops->write_std(new_tss_base, | 1947 | ret = ops->write_std(new_tss_base, |
1965 | &tss_seg.prev_task_link, | 1948 | &tss_seg.prev_task_link, |
1966 | sizeof tss_seg.prev_task_link, | 1949 | sizeof tss_seg.prev_task_link, |
1967 | ctxt->vcpu, &err); | 1950 | ctxt->vcpu, &ctxt->exception); |
1968 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 1951 | if (ret == X86EMUL_PROPAGATE_FAULT) |
1969 | /* FIXME: need to provide precise fault address */ | 1952 | /* FIXME: need to provide precise fault address */ |
1970 | emulate_pf(ctxt); | ||
1971 | return ret; | 1953 | return ret; |
1972 | } | ||
1973 | } | 1954 | } |
1974 | 1955 | ||
1975 | return load_state_from_tss16(ctxt, ops, &tss_seg); | 1956 | return load_state_from_tss16(ctxt, ops, &tss_seg); |
@@ -2072,33 +2053,27 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, | |||
2072 | { | 2053 | { |
2073 | struct tss_segment_32 tss_seg; | 2054 | struct tss_segment_32 tss_seg; |
2074 | int ret; | 2055 | int ret; |
2075 | u32 err, new_tss_base = get_desc_base(new_desc); | 2056 | u32 new_tss_base = get_desc_base(new_desc); |
2076 | 2057 | ||
2077 | ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 2058 | ret = ops->read_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
2078 | &err); | 2059 | &ctxt->exception); |
2079 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 2060 | if (ret == X86EMUL_PROPAGATE_FAULT) |
2080 | /* FIXME: need to provide precise fault address */ | 2061 | /* FIXME: need to provide precise fault address */ |
2081 | emulate_pf(ctxt); | ||
2082 | return ret; | 2062 | return ret; |
2083 | } | ||
2084 | 2063 | ||
2085 | save_state_to_tss32(ctxt, ops, &tss_seg); | 2064 | save_state_to_tss32(ctxt, ops, &tss_seg); |
2086 | 2065 | ||
2087 | ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 2066 | ret = ops->write_std(old_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
2088 | &err); | 2067 | &ctxt->exception); |
2089 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 2068 | if (ret == X86EMUL_PROPAGATE_FAULT) |
2090 | /* FIXME: need to provide precise fault address */ | 2069 | /* FIXME: need to provide precise fault address */ |
2091 | emulate_pf(ctxt); | ||
2092 | return ret; | 2070 | return ret; |
2093 | } | ||
2094 | 2071 | ||
2095 | ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, | 2072 | ret = ops->read_std(new_tss_base, &tss_seg, sizeof tss_seg, ctxt->vcpu, |
2096 | &err); | 2073 | &ctxt->exception); |
2097 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 2074 | if (ret == X86EMUL_PROPAGATE_FAULT) |
2098 | /* FIXME: need to provide precise fault address */ | 2075 | /* FIXME: need to provide precise fault address */ |
2099 | emulate_pf(ctxt); | ||
2100 | return ret; | 2076 | return ret; |
2101 | } | ||
2102 | 2077 | ||
2103 | if (old_tss_sel != 0xffff) { | 2078 | if (old_tss_sel != 0xffff) { |
2104 | tss_seg.prev_task_link = old_tss_sel; | 2079 | tss_seg.prev_task_link = old_tss_sel; |
@@ -2106,12 +2081,10 @@ static int task_switch_32(struct x86_emulate_ctxt *ctxt, | |||
2106 | ret = ops->write_std(new_tss_base, | 2081 | ret = ops->write_std(new_tss_base, |
2107 | &tss_seg.prev_task_link, | 2082 | &tss_seg.prev_task_link, |
2108 | sizeof tss_seg.prev_task_link, | 2083 | sizeof tss_seg.prev_task_link, |
2109 | ctxt->vcpu, &err); | 2084 | ctxt->vcpu, &ctxt->exception); |
2110 | if (ret == X86EMUL_PROPAGATE_FAULT) { | 2085 | if (ret == X86EMUL_PROPAGATE_FAULT) |
2111 | /* FIXME: need to provide precise fault address */ | 2086 | /* FIXME: need to provide precise fault address */ |
2112 | emulate_pf(ctxt); | ||
2113 | return ret; | 2087 | return ret; |
2114 | } | ||
2115 | } | 2088 | } |
2116 | 2089 | ||
2117 | return load_state_from_tss32(ctxt, ops, &tss_seg); | 2090 | return load_state_from_tss32(ctxt, ops, &tss_seg); |