[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [RFC PATCH 14/16] sev/emulate: Handle some non-emulable HVM paths
From: Andrei Semenov <andrei.semenov@xxxxxxxxxx> Some code paths are not emulable under SEV or needs special handling. Signed-off-by: Andrei Semenov <andrei.semenov@xxxxxxxxxx> Signed-off-by: Teddy Astie <teddy.astie@xxxxxxxxxx> --- xen/arch/x86/hvm/emulate.c | 137 ++++++++++++++++++++++++++++++++----- xen/arch/x86/hvm/hvm.c | 13 ++++ 2 files changed, 133 insertions(+), 17 deletions(-) diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c index 6ed8e03475..7ac3be2d59 100644 --- a/xen/arch/x86/hvm/emulate.c +++ b/xen/arch/x86/hvm/emulate.c @@ -26,6 +26,7 @@ #include <asm/hvm/hvm.h> #include <asm/hvm/monitor.h> #include <asm/hvm/support.h> +#include <asm/hvm/svm/sev.h> #include <asm/iocap.h> #include <asm/vm_event.h> @@ -689,6 +690,9 @@ static void *hvmemul_map_linear_addr( goto unhandleable; } + if ( is_sev_domain(curr->domain) && (nr_frames > 1) ) + goto unhandleable; + for ( i = 0; i < nr_frames; i++ ) { enum hvm_translation_result res; @@ -703,8 +707,16 @@ static void *hvmemul_map_linear_addr( /* Error checking. Confirm that the current slot is clean. */ ASSERT(mfn_x(*mfn) == 0); - res = hvm_translate_get_page(curr, addr, true, pfec, + if ( is_sev_domain(curr->domain) ) + { + struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io; + unsigned long gpa = pfn_to_paddr(hvio->mmio_gpfn) | (addr & ~PAGE_MASK); + res = hvm_translate_get_page(curr, gpa, false, pfec, &pfinfo, &page, &gfn, &p2mt); + } + else + res = hvm_translate_get_page(curr, addr, true, pfec, + &pfinfo, &page, &gfn, &p2mt); switch ( res ) { @@ -1173,6 +1185,7 @@ static int hvmemul_linear_mmio_access( dir, buffer_offset); paddr_t gpa; unsigned long one_rep = 1; + unsigned int chunk; int rc; if ( cache == NULL ) @@ -1183,21 +1196,50 @@ static int hvmemul_linear_mmio_access( ASSERT_UNREACHABLE(); return X86EMUL_UNHANDLEABLE; } + + chunk = min_t(unsigned int, size, PAGE_SIZE - offset); if ( known_gpfn ) gpa = pfn_to_paddr(hvio->mmio_gpfn) | offset; else { - rc = hvmemul_linear_to_phys(gla, &gpa, size, &one_rep, pfec, + if ( is_sev_domain(current->domain) ) + gpa = pfn_to_paddr(hvio->mmio_gpfn) | offset; + else + { + rc = hvmemul_linear_to_phys(gla, &gpa, chunk, &one_rep, pfec, + hvmemul_ctxt); + if ( rc != X86EMUL_OKAY ) + return rc; + } + + latch_linear_to_phys(hvio, gla, gpa, dir == IOREQ_WRITE); + } + + for ( ;; ) + { + rc = hvmemul_phys_mmio_access(cache, gpa, chunk, dir, buffer, buffer_offset); + if ( rc != X86EMUL_OKAY ) + break; + + gla += chunk; + buffer_offset += chunk; + size -= chunk; + + if ( size == 0 ) + break; + + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + + chunk = min_t(unsigned int, size, PAGE_SIZE); + rc = hvmemul_linear_to_phys(gla, &gpa, chunk, &one_rep, pfec, hvmemul_ctxt); if ( rc != X86EMUL_OKAY ) return rc; - - latch_linear_to_phys(hvio, gla, gpa, dir == IOREQ_WRITE); } - return hvmemul_phys_mmio_access(cache, gpa, size, dir, buffer, - buffer_offset); + return rc; } static inline int hvmemul_linear_mmio_read( @@ -1254,6 +1296,9 @@ static int linear_read(unsigned long addr, unsigned int bytes, void *p_data, { unsigned int part1 = PAGE_SIZE - offset; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + /* Split the access at the page boundary. */ rc = linear_read(addr, part1, p_data, pfec, hvmemul_ctxt); if ( rc != X86EMUL_OKAY ) @@ -1278,11 +1323,25 @@ static int linear_read(unsigned long addr, unsigned int bytes, void *p_data, * upon replay) the RAM access for anything that's ahead of or past MMIO, * i.e. in RAM. */ - cache = hvmemul_find_mmio_cache(hvio, start, IOREQ_READ, ~0); - if ( !cache || - addr + bytes <= start + cache->skip || - addr >= start + cache->size ) - rc = hvm_copy_from_guest_linear(p_data, addr, bytes, pfec, &pfinfo); + cache = hvmemul_find_mmio_cache(hvio, start, IOREQ_READ, ~0); + if ( !cache || + addr + bytes <= start + cache->skip || + addr >= start + cache->size ) + { + if ( is_sev_domain(current->domain) ) + { + if ( hvio->mmio_gpfn ) + { + paddr_t gpa; + gpa = pfn_to_paddr(hvio->mmio_gpfn) | (addr & ~PAGE_MASK); + rc = hvm_copy_from_guest_phys(p_data, gpa, bytes); + } + else + return X86EMUL_UNHANDLEABLE; + } + else + rc = hvm_copy_from_guest_linear(p_data, addr, bytes, pfec, &pfinfo); + } switch ( rc ) { @@ -1325,6 +1384,9 @@ static int linear_write(unsigned long addr, unsigned int bytes, void *p_data, { unsigned int part1 = PAGE_SIZE - offset; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + /* Split the access at the page boundary. */ rc = linear_write(addr, part1, p_data, pfec, hvmemul_ctxt); if ( rc != X86EMUL_OKAY ) @@ -1340,9 +1402,23 @@ static int linear_write(unsigned long addr, unsigned int bytes, void *p_data, /* See commentary in linear_read(). */ cache = hvmemul_find_mmio_cache(hvio, start, IOREQ_WRITE, ~0); if ( !cache || - addr + bytes <= start + cache->skip || - addr >= start + cache->size ) - rc = hvm_copy_to_guest_linear(addr, p_data, bytes, pfec, &pfinfo); + addr + bytes <= start + cache->skip || + addr >= start + cache->size ) + { + if ( is_sev_domain(current->domain) ) + { + if ( hvio->mmio_gpfn ) + { + paddr_t gpa; + gpa = pfn_to_paddr(hvio->mmio_gpfn) | (addr & ~PAGE_MASK); + rc = hvm_copy_to_guest_phys(gpa, p_data, bytes, current); + } + else + return X86EMUL_UNHANDLEABLE; + } + else + rc = hvm_copy_to_guest_linear(addr, p_data, bytes, pfec, &pfinfo); + } switch ( rc ) { @@ -1430,7 +1506,12 @@ int cf_check hvmemul_insn_fetch( if ( !bytes || unlikely((insn_off + bytes) > hvmemul_ctxt->insn_buf_bytes) ) { - int rc = __hvmemul_read(x86_seg_cs, offset, p_data, bytes, + int rc; + + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + + rc = __hvmemul_read(x86_seg_cs, offset, p_data, bytes, hvm_access_insn_fetch, hvmemul_ctxt); if ( rc == X86EMUL_OKAY && bytes ) @@ -1485,6 +1566,7 @@ static int cf_check hvmemul_write( if ( !known_gla(addr, bytes, pfec) ) { mapping = hvmemul_map_linear_addr(addr, bytes, pfec, hvmemul_ctxt); + if ( IS_ERR(mapping) ) return ~PTR_ERR(mapping); } @@ -1719,6 +1801,9 @@ static int cf_check hvmemul_cmpxchg( int rc; void *mapping = NULL; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + rc = hvmemul_virtual_to_linear( seg, offset, bytes, NULL, hvm_access_write, hvmemul_ctxt, &addr); if ( rc != X86EMUL_OKAY ) @@ -1821,6 +1906,9 @@ static int cf_check hvmemul_rep_ins( p2m_type_t p2mt; int rc; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + rc = hvmemul_virtual_to_linear( dst_seg, dst_offset, bytes_per_rep, reps, hvm_access_write, hvmemul_ctxt, &addr); @@ -1899,6 +1987,9 @@ static int cf_check hvmemul_rep_outs( p2m_type_t p2mt; int rc; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + if ( unlikely(hvmemul_ctxt->set_context) ) return hvmemul_rep_outs_set_context(dst_port, bytes_per_rep, reps); @@ -1944,6 +2035,9 @@ static int cf_check hvmemul_rep_movs( int rc, df = !!(ctxt->regs->eflags & X86_EFLAGS_DF); char *buf; + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + rc = hvmemul_virtual_to_linear( src_seg, src_offset, bytes_per_rep, reps, hvm_access_read, hvmemul_ctxt, &saddr); @@ -2109,9 +2203,13 @@ static int cf_check hvmemul_rep_stos( paddr_t gpa; p2m_type_t p2mt; bool df = ctxt->regs->eflags & X86_EFLAGS_DF; - int rc = hvmemul_virtual_to_linear(seg, offset, bytes_per_rep, reps, - hvm_access_write, hvmemul_ctxt, &addr); + int rc; + + if ( is_sev_domain(current->domain) ) + return X86EMUL_UNHANDLEABLE; + rc = hvmemul_virtual_to_linear(seg, offset, bytes_per_rep, reps, + hvm_access_write, hvmemul_ctxt, &addr); if ( rc != X86EMUL_OKAY ) return rc; @@ -2770,6 +2868,7 @@ static int _hvm_emulate_one(struct hvm_emulate_ctxt *hvmemul_ctxt, struct vcpu *curr = current; uint32_t new_intr_shadow; struct hvm_vcpu_io *hvio = &curr->arch.hvm.hvm_io; + int rc; /* @@ -2983,6 +3082,9 @@ void hvm_emulate_init_per_insn( unsigned int pfec = PFEC_page_present | PFEC_insn_fetch; unsigned long addr; + if ( is_sev_domain(current->domain) ) + goto out; + if ( hvmemul_ctxt->seg_reg[x86_seg_ss].dpl == 3 ) pfec |= PFEC_user_mode; @@ -3000,6 +3102,7 @@ void hvm_emulate_init_per_insn( sizeof(hvmemul_ctxt->insn_buf) : 0; } +out: hvmemul_ctxt->is_mem_access = false; } diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index e1bcf8e086..d3060329fb 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -56,6 +56,7 @@ #include <asm/hvm/monitor.h> #include <asm/hvm/viridian.h> #include <asm/hvm/vm_event.h> +#include <asm/hvm/svm/sev.h> #include <asm/altp2m.h> #include <asm/mtrr.h> #include <asm/apic.h> @@ -3477,6 +3478,9 @@ enum hvm_translation_result hvm_copy_to_guest_linear( unsigned long addr, const void *buf, unsigned int size, uint32_t pfec, pagefault_info_t *pfinfo) { + if ( is_sev_domain(current->domain) ) + return HVMTRANS_unhandleable; + return __hvm_copy((void *)buf /* HVMCOPY_to_guest doesn't modify */, addr, size, current, HVMCOPY_to_guest | HVMCOPY_linear, PFEC_page_present | PFEC_write_access | pfec, pfinfo); @@ -3486,6 +3490,9 @@ enum hvm_translation_result hvm_copy_from_guest_linear( void *buf, unsigned long addr, unsigned int size, uint32_t pfec, pagefault_info_t *pfinfo) { + if ( is_sev_domain(current->domain) ) + return HVMTRANS_unhandleable; + return __hvm_copy(buf, addr, size, current, HVMCOPY_from_guest | HVMCOPY_linear, PFEC_page_present | pfec, pfinfo); @@ -3495,6 +3502,9 @@ enum hvm_translation_result hvm_copy_from_vcpu_linear( void *buf, unsigned long addr, unsigned int size, struct vcpu *v, unsigned int pfec) { + if ( is_sev_domain(v->domain) ) + return HVMTRANS_unhandleable; + return __hvm_copy(buf, addr, size, v, HVMCOPY_from_guest | HVMCOPY_linear, PFEC_page_present | pfec, NULL); @@ -3522,6 +3532,9 @@ unsigned int clear_user_hvm(void *to, unsigned int len) { int rc; + if ( is_sev_domain(current->domain) ) + return HVMTRANS_unhandleable; + if ( current->hcall_compat && is_compat_arg_xlat_range(to, len) ) { memset(to, 0x00, len); -- 2.49.0 Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |