Implement FastABI basing on docs/guest-guide/x86/fastabi.pandoc and defined ABI.
Signed-off-by: Teddy Astie <teddy.as...@vates.tech> --- xen/arch/x86/cpuid.c | 3 + xen/arch/x86/domain.c | 71 ++++++++++ xen/arch/x86/hvm/hvm.c | 81 +++++++++++- xen/arch/x86/hvm/hypercall.c | 22 ++++ xen/arch/x86/include/asm/fastabi.h | 17 +++ xen/common/Kconfig | 6 + xen/common/Makefile | 1 + xen/common/domain.c | 179 ++++++++++++++++++++++++++ xen/common/event_channel.c | 199 +++++++++++++++++++++++++++++ xen/common/fastabi.c | 49 +++++++ xen/common/grant_table.c | 44 +++++++ xen/common/kernel.c | 33 +++++ xen/common/memory.c | 110 ++++++++++++++++ xen/common/sched/core.c | 109 +++++++++++++++- xen/include/public/event_channel.h | 7 + xen/include/public/fastabi.h | 20 +++ xen/include/xen/fastabi.h | 21 +++ 17 files changed, 970 insertions(+), 2 deletions(-) create mode 100644 xen/arch/x86/include/asm/fastabi.h create mode 100644 xen/common/fastabi.c create mode 100644 xen/include/public/fastabi.h create mode 100644 xen/include/xen/fastabi.h diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c index 8dc68945f7..b1f90c1d91 100644 --- a/xen/arch/x86/cpuid.c +++ b/xen/arch/x86/cpuid.c @@ -153,6 +153,9 @@ static void cpuid_hypervisor_leaves(const struct vcpu *v, uint32_t leaf, */ res->a |= XEN_HVM_CPUID_UPCALL_VECTOR; + if ( IS_ENABLED(CONFIG_FASTABI) && is_hvm_vcpu(v) ) + res->a |= XEN_HVM_CPUID_FASTABI; + break; case 5: /* PV-specific parameters */ diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index 56c3816187..44416869a3 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -71,6 +71,10 @@ #include <public/sysctl.h> #include <public/hvm/hvm_vcpu.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_COMPAT #include <compat/vcpu.h> #endif @@ -1695,6 +1699,73 @@ long do_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } +#ifdef CONFIG_FASTABI +void do_vcpu_fast_op(struct cpu_user_regs *regs) +{ + long rc = 0; + struct domain *d = current->domain; + struct vcpu *v; + + unsigned long cmd = fastabi_value_n(regs, 1); + unsigned long vcpuid = fastabi_value_n(regs, 2); + + if ( (v = domain_vcpu(d, vcpuid)) == NULL ) + { + fastabi_value_n(regs, 0) = -ENOENT; + return; + } + + switch ( cmd ) + { + case VCPUOP_send_nmi: + if ( !test_and_set_bool(v->arch.nmi_pending) ) + vcpu_kick(v); + break; + + + case VCPUOP_register_vcpu_time_phys_area: + { + struct vcpu_register_time_memory_area area = { + .addr.p = fastabi_value_n(regs, 3) + }; + + rc = -ENOSYS; + if ( 0 /* TODO: Dom's XENFEAT_vcpu_time_phys_area setting */ ) + break; + + rc = map_guest_area(v, area.addr.p, + sizeof(vcpu_time_info_t), + &v->arch.time_guest_area, + time_area_populate); + break; + } + + case VCPUOP_get_physid: + { + rc = -EINVAL; + if ( !is_hwdom_pinned_vcpu(v) ) + break; + + fastabi_value_n(regs, 3) = + (uint64_t)x86_cpu_to_apicid[v->vcpu_id] | + ((uint64_t)acpi_get_processor_id(v->vcpu_id) << 32); + + rc = 0; + break; + } + + default: + rc = common_vcpu_fast_op(regs, cmd, v); + break; + } + + if ( rc == -ERESTART ) + fastabi_make_continuation(); + else + fastabi_value_n(regs, 0) = rc; +} +#endif + /* * Notes on PV segment handling: * - 32bit: All data from the GDT/LDT. diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c index 8bf59c63fe..eca052e109 100644 --- a/xen/arch/x86/hvm/hvm.c +++ b/xen/arch/x86/hvm/hvm.c @@ -68,6 +68,10 @@ #include <compat/hvm/hvm_op.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + bool __read_mostly hvm_enabled; #ifdef DBG_LEVEL_0 @@ -4548,7 +4552,7 @@ static int hvmop_get_param(struct xen_hvm_param *op) rc = -EINVAL; if ( is_hvm_domain(d) && !(rc = hvm_get_param(d, op->index, &op->value)) ) - HVM_DBG_LOG(DBG_LEVEL_HCALL, "get param %u = %"PRIx64, a.index, a.value); + HVM_DBG_LOG(DBG_LEVEL_HCALL, "get param %u = %"PRIx64, op->index, op->value); rcu_unlock_domain(d); return rc; @@ -5224,6 +5228,81 @@ long do_hvm_op(unsigned long op, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } +#ifdef CONFIG_FASTABI +void do_hvm_fast_op(struct cpu_user_regs *regs) +{ + long rc = 0; + unsigned long op = fastabi_value_n(regs, 1); + + switch ( op ) + { + case HVMOP_set_evtchn_upcall_vector: + { + struct xen_hvm_evtchn_upcall_vector op = { + .vcpu = fastabi_value_n(regs, 2), + .vector = fastabi_value_n(regs, 3), + }; + + rc = hvmop_set_evtchn_upcall_vector(op); + break; + } + + case HVMOP_set_param: + { + struct xen_hvm_param op = { + .domid = fastabi_value_n(regs, 2), + .index = fastabi_value_n(regs, 3), + .value = fastabi_value_n(regs, 4), + }; + + rc = hvmop_set_param(op); + break; + } + + case HVMOP_get_param: + { + struct xen_hvm_param op = { + .domid = fastabi_value_n(regs, 2), + .index = fastabi_value_n(regs, 3), + }; + + rc = hvmop_get_param(&op); + if ( !rc ) + fastabi_value_n(regs, 4) = op.value; + break; + } + + case HVMOP_flush_tlbs: + rc = hvmop_flush_tlb_all(); + break; + + case HVMOP_get_time: + fastabi_value_n(regs, 2) = NOW(); + break; + + case HVMOP_get_mem_type: + { + struct xen_hvm_get_mem_type op = { + .domid = fastabi_value_n(regs, 2), + .pfn = fastabi_value_n(regs, 3), + }; + + rc = hvmop_get_mem_type(&op); + + if ( !rc ) + fastabi_value_n(regs, 4) = op.mem_type; + break; + } + + default: + rc = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = rc; +} +#endif + int hvm_debug_op(struct vcpu *v, int32_t op) { int rc = 0; diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c index 6f8dfdff4a..3759a1aa58 100644 --- a/xen/arch/x86/hvm/hypercall.c +++ b/xen/arch/x86/hvm/hypercall.c @@ -19,6 +19,10 @@ #include <public/hvm/hvm_op.h> #include <public/hvm/params.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + long hvm_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) { long rc; @@ -155,6 +159,24 @@ int hvm_hypercall(struct cpu_user_regs *regs) curr->hcall_preempted = false; + #ifdef CONFIG_FASTABI + if ( eax & 0x40000000U && is_hvm_domain(currd) && mode == X86_MODE_64BIT ) + { + unsigned long index = eax & ~0x40000000U; + HVM_DBG_LOG(DBG_LEVEL_HCALL, + "fasthcall%lu(%lx, %lx, %lx, %lx, %lx, %lx, %lx)", + index, fastabi_value_n(regs, 1), fastabi_value_n(regs, 2), + fastabi_value_n(regs, 3), fastabi_value_n(regs, 4), + fastabi_value_n(regs, 5), fastabi_value_n(regs, 6), + fastabi_value_n(regs, 7)); + + fastabi_dispatch(index, regs); + + hvmemul_cache_restore(curr, token); + return HVM_HCALL_completed; + } + #endif + if ( mode == 8 ) { HVM_DBG_LOG(DBG_LEVEL_HCALL, "hcall%lu(%lx, %lx, %lx, %lx, %lx)", diff --git a/xen/arch/x86/include/asm/fastabi.h b/xen/arch/x86/include/asm/fastabi.h new file mode 100644 index 0000000000..914504c63d --- /dev/null +++ b/xen/arch/x86/include/asm/fastabi.h @@ -0,0 +1,17 @@ +#ifndef XEN_ASM_FASTABI_H +#define XEN_ASM_FASTABI_H + +#include <asm/current.h> + +#define fastabi_param_reg0 rax +#define fastabi_param_reg1 rdi +#define fastabi_param_reg2 rsi +#define fastabi_param_reg3 r8 +#define fastabi_param_reg4 r9 +#define fastabi_param_reg5 r10 +#define fastabi_param_reg6 r11 +#define fastabi_param_reg7 r12 + +#define fastabi_value_n(regs, n) (regs)->fastabi_param_reg##n + +#endif /* XEN_ASM_FASTABI_H */ \ No newline at end of file diff --git a/xen/common/Kconfig b/xen/common/Kconfig index 65f07289dd..71bb4e4f2d 100644 --- a/xen/common/Kconfig +++ b/xen/common/Kconfig @@ -636,4 +636,10 @@ config PM_STATS Enable collection of performance management statistics to aid in analyzing and tuning power/performance characteristics of the system +config FASTABI + depends on X86 && HVM + bool "Fast HVM ABI (unsupported)" + help + Add support for a alternative fast HVM ABI. + endmenu diff --git a/xen/common/Makefile b/xen/common/Makefile index 98f0873056..362e8f61d7 100644 --- a/xen/common/Makefile +++ b/xen/common/Makefile @@ -62,6 +62,7 @@ obj-y += wait.o obj-bin-y += warning.init.o obj-$(CONFIG_XENOPROF) += xenoprof.o obj-y += xmalloc_tlsf.o +obj-$(CONFIG_FASTABI) += fastabi.o obj-bin-$(CONFIG_X86) += $(foreach n,decompress bunzip2 unxz unlzma lzo unlzo unlz4 unzstd earlycpio,$(n).init.o) diff --git a/xen/common/domain.c b/xen/common/domain.c index 303c338ef2..5a641403b9 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -45,6 +45,10 @@ #include <xen/trace.h> #include <asm/setup.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_X86 #include <asm/guest.h> #endif @@ -2266,6 +2270,181 @@ long common_vcpu_op(int cmd, struct vcpu *v, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } +#ifdef CONFIG_FASTABI +long common_vcpu_fast_op(struct cpu_user_regs *regs, int cmd, struct vcpu *v) +{ + long rc = 0; + struct domain *d = v->domain; + unsigned int vcpuid = v->vcpu_id; + + switch ( cmd ) + { + case VCPUOP_initialise: + rc = arch_initialise_vcpu(v, (XEN_GUEST_HANDLE(void)) { + (void *)fastabi_value_n(regs, 2) }); + break; + + case VCPUOP_up: + { + bool wake = false; + + domain_lock(d); + if ( !v->is_initialised ) + rc = -EINVAL; + else + wake = test_and_clear_bit(_VPF_down, &v->pause_flags); + domain_unlock(d); + if ( wake ) + vcpu_wake(v); + } + + break; + + case VCPUOP_down: + for_each_vcpu ( d, v ) + if ( !test_bit(_VPF_down, &v->pause_flags) ) + { + rc = 1; + break; + } + + if ( !rc ) /* Last vcpu going down? */ + { + domain_shutdown(d, SHUTDOWN_poweroff); + break; + } + + rc = 0; + v = d->vcpu[vcpuid]; + + if ( !test_and_set_bit(_VPF_down, &v->pause_flags) ) + vcpu_sleep_nosync(v); + + break; + + case VCPUOP_is_up: + rc = !(v->pause_flags & VPF_down); + break; + + case VCPUOP_get_runstate_info: + { + struct vcpu_runstate_info runstate; + vcpu_runstate_get(v, &runstate); + + fastabi_value_n(regs, 2) = runstate.state; + fastabi_value_n(regs, 3) = runstate.state_entry_time; + fastabi_value_n(regs, 4) = runstate.time[0]; + fastabi_value_n(regs, 5) = runstate.time[1]; + fastabi_value_n(regs, 6) = runstate.time[2]; + fastabi_value_n(regs, 7) = runstate.time[3]; + break; + } + + case VCPUOP_set_periodic_timer: + { + uint64_t period_ns = fastabi_value_n(regs, 3); + + if ( period_ns < MILLISECS(1) ) + return -EINVAL; + + if ( period_ns > STIME_DELTA_MAX ) + return -EINVAL; + + vcpu_set_periodic_timer(v, period_ns); + + break; + } + + case VCPUOP_stop_periodic_timer: + vcpu_set_periodic_timer(v, 0); + break; + + case VCPUOP_set_singleshot_timer: + { + struct vcpu_set_singleshot_timer set = { + .timeout_abs_ns = fastabi_value_n(regs, 3), + .flags = fastabi_value_n(regs, 4), + }; + + if ( v != current ) + return -EINVAL; + + if ( set.timeout_abs_ns < NOW() ) + { + /* + * Simplify the logic if the timeout has already expired and just + * inject the event. + */ + stop_timer(&v->singleshot_timer); + send_timer_event(v); + break; + } + + migrate_timer(&v->singleshot_timer, smp_processor_id()); + set_timer(&v->singleshot_timer, set.timeout_abs_ns); + + break; + } + + case VCPUOP_stop_singleshot_timer: + if ( v != current ) + return -EINVAL; + + stop_timer(&v->singleshot_timer); + + break; + + case VCPUOP_register_vcpu_info: + { + struct vcpu_register_vcpu_info info = { + .mfn = fastabi_value_n(regs, 3), + .offset = fastabi_value_n(regs, 4) + }; + paddr_t gaddr; + + rc = -EINVAL; + gaddr = gfn_to_gaddr(_gfn(info.mfn)) + info.offset; + if ( !~gaddr || + gfn_x(gaddr_to_gfn(gaddr)) != info.mfn ) + break; + + /* Preliminary check only; see map_guest_area(). */ + rc = -EBUSY; + if ( v->vcpu_info_area.pg ) + break; + + /* See the BUILD_BUG_ON() in vcpu_info_populate(). */ + rc = map_guest_area(v, gaddr, sizeof(vcpu_info_t), + &v->vcpu_info_area, vcpu_info_populate); + break; + } + + case VCPUOP_register_runstate_phys_area: + { + struct vcpu_register_runstate_memory_area area = { + .addr.p = fastabi_value_n(regs, 3) + }; + + rc = -ENOSYS; + if ( 0 /* TODO: Dom's XENFEAT_runstate_phys_area setting */ ) + break; + + rc = map_guest_area(v, area.addr.p, + sizeof(struct vcpu_runstate_info), + &v->runstate_guest_area, + runstate_area_populate); + break; + } + + default: + rc = -ENOSYS; + break; + } + + return rc; +} +#endif + #ifdef arch_vm_assist_valid_mask long do_vm_assist(unsigned int cmd, unsigned int type) { diff --git a/xen/common/event_channel.c b/xen/common/event_channel.c index c8c1bfa615..9c8bc0f354 100644 --- a/xen/common/event_channel.c +++ b/xen/common/event_channel.c @@ -34,6 +34,10 @@ #include <public/event_channel.h> #include <xsm/xsm.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_PV_SHIM #include <asm/guest.h> #endif @@ -1507,6 +1511,201 @@ long do_event_channel_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } +#ifdef CONFIG_FASTABI +void do_event_channel_fast_op(struct cpu_user_regs *regs) +{ + long rc; + uint64_t cmd = fastabi_value_n(regs, 1); + + switch ( cmd ) + { + case EVTCHNOP_alloc_unbound: { + struct evtchn_alloc_unbound alloc_unbound = { + .dom = fastabi_value_n(regs, 2), + .remote_dom = fastabi_value_n(regs, 3), + .port = 0, + }; + rc = evtchn_alloc_unbound(&alloc_unbound, 0); + + if ( !rc ) + fastabi_value_n(regs, 4) = alloc_unbound.port; + break; + } + + case EVTCHNOP_bind_interdomain: { + struct evtchn_bind_interdomain bind_interdomain = { + .remote_dom = fastabi_value_n(regs, 2), + .remote_port = fastabi_value_n(regs, 3), + .local_port = 0, + }; + rc = evtchn_bind_interdomain(&bind_interdomain, current->domain, 0); + + if ( !rc ) + fastabi_value_n(regs, 4) = bind_interdomain.local_port; + break; + } + + case EVTCHNOP_bind_virq: { + struct evtchn_bind_virq bind_virq = { + .virq = fastabi_value_n(regs, 2), + .vcpu = fastabi_value_n(regs, 3), + .port = 0, + }; + rc = evtchn_bind_virq(&bind_virq, 0); + + if ( !rc ) + fastabi_value_n(regs, 4) = bind_virq.port; + break; + } + + case EVTCHNOP_bind_ipi: { + struct evtchn_bind_ipi bind_ipi = { + .vcpu = fastabi_value_n(regs, 2), + .port = 0, + }; + rc = evtchn_bind_ipi(&bind_ipi); + + if ( !rc ) + fastabi_value_n(regs, 4) = bind_ipi.port; + break; + } + + case EVTCHNOP_bind_pirq: { + struct evtchn_bind_pirq bind_pirq = { + .pirq = fastabi_value_n(regs, 2), + .flags = fastabi_value_n(regs, 3), + }; + rc = evtchn_bind_pirq(&bind_pirq); + + if ( !rc ) + fastabi_value_n(regs, 4) = bind_pirq.port; + break; + } + + case EVTCHNOP_close: { + struct evtchn_close close = { .port = fastabi_value_n(regs, 2) }; + rc = evtchn_close(current->domain, close.port, 1); + break; + } + + case EVTCHNOP_send: { + struct evtchn_send send = { .port = fastabi_value_n(regs, 2) }; + rc = evtchn_send(current->domain, send.port); + break; + } + + case EVTCHNOP_status: { + struct evtchn_status status = { + .dom = fastabi_value_n(regs, 2), + .port = fastabi_value_n(regs, 3), + }; + rc = evtchn_status(&status); + + if ( !rc ) + { + fastabi_value_n(regs, 4) = status.status; + fastabi_value_n(regs, 5) = status.vcpu; + + switch (status.status) + { + case EVTCHNSTAT_unbound: + fastabi_value_n(regs, 6) = status.u.unbound.dom; + break; + case EVTCHNSTAT_interdomain: + fastabi_value_n(regs, 6) = status.u.interdomain.dom; + fastabi_value_n(regs, 7) = status.u.interdomain.port; + break; + case EVTCHNSTAT_pirq: + fastabi_value_n(regs, 6) = status.u.pirq; + break; + case EVTCHNSTAT_virq: + fastabi_value_n(regs, 6) = status.u.virq; + break; + default: + break; + } + } + break; + } + + case EVTCHNOP_bind_vcpu: { + struct evtchn_bind_vcpu bind_vcpu = { + .vcpu = fastabi_value_n(regs, 2), + .port = fastabi_value_n(regs, 3) + }; + rc = evtchn_bind_vcpu(bind_vcpu.port, bind_vcpu.vcpu); + break; + } + + case EVTCHNOP_unmask: { + struct evtchn_unmask unmask = { .port = fastabi_value_n(regs, 2) }; + rc = evtchn_unmask(unmask.port); + break; + } + + case EVTCHNOP_reset: + case EVTCHNOP_reset_cont: { + struct evtchn_reset reset = { .dom = fastabi_value_n(regs, 2) }; + struct domain *d; + + d = rcu_lock_domain_by_any_id(reset.dom); + if ( d == NULL ) + { + rc = -ESRCH; + break; + } + + rc = xsm_evtchn_reset(XSM_TARGET, current->domain, d); + if ( !rc ) + rc = evtchn_reset(d, cmd == EVTCHNOP_reset_cont); + + rcu_unlock_domain(d); + + if ( rc == -ERESTART ) + { + fastabi_value_n(regs, 1) = EVTCHNOP_reset_cont; + fastabi_make_continuation(); + return; + } + break; + } + + case EVTCHNOP_init_control: { + struct evtchn_init_control init_control = { + .control_gfn = fastabi_value_n(regs, 2), + .offset = fastabi_value_n(regs, 3), + .vcpu = fastabi_value_n(regs, 4) + }; + rc = evtchn_fifo_init_control(&init_control); + + if ( !rc ) + fastabi_value_n(regs, 5) = init_control.link_bits; + break; + } + + case EVTCHNOP_expand_array: { + struct evtchn_expand_array expand_array = { .array_gfn = fastabi_value_n(regs, 2) }; + rc = evtchn_fifo_expand_array(&expand_array); + break; + } + + case EVTCHNOP_set_priority: { + struct evtchn_set_priority set_priority = { + .port = fastabi_value_n(regs, 2), + .priority = fastabi_value_n(regs, 3), + }; + rc = evtchn_set_priority(&set_priority); + break; + } + + default: + rc = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = rc; +} +#endif int alloc_unbound_xen_event_channel( struct domain *ld, unsigned int lvcpu, domid_t remote_domid, diff --git a/xen/common/fastabi.c b/xen/common/fastabi.c new file mode 100644 index 0000000000..96a3b05ee7 --- /dev/null +++ b/xen/common/fastabi.c @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <xen/errno.h> +#include <xen/fastabi.h> +#include <xen/sched.h> + +#include <public/xen.h> + +void fastabi_make_continuation(void) +{ + current->hcall_preempted = true; +} + +void fastabi_dispatch(unsigned long index, struct cpu_user_regs *regs) +{ + switch (index) { + case __HYPERVISOR_memory_op: + do_memory_fast_op(regs); + break; + + case __HYPERVISOR_xen_version: + do_xen_version_fast_op(regs); + break; + + case __HYPERVISOR_grant_table_op: + do_grant_table_fast_op(regs); + break; + + case __HYPERVISOR_vcpu_op: + do_vcpu_fast_op(regs); + break; + + case __HYPERVISOR_sched_op: + do_sched_fast_op(regs); + break; + + case __HYPERVISOR_event_channel_op: + do_event_channel_fast_op(regs); + break; + + case __HYPERVISOR_hvm_op: + do_hvm_fast_op(regs); + break; + + default: + fastabi_value_n(regs, 0) = -ENOSYS; + break; + } +} \ No newline at end of file diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 3c3bbca2fc..1476e5e5ca 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -45,6 +45,10 @@ #include <asm/flushtlb.h> #include <asm/guest_atomics.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_PV_SHIM #include <asm/guest.h> #endif @@ -3826,6 +3830,46 @@ long do_grant_table_op( return rc; } +#ifdef CONFIG_FASTABI +void do_grant_table_fast_op(struct cpu_user_regs *regs) +{ + long rc = 0; + unsigned int cmd = fastabi_value_n(regs, 1); + + switch (cmd) + { + case GNTTABOP_query_size: + { + struct grant_table *gt = current->domain->grant_table; + + grant_read_lock(gt); + fastabi_value_n(regs, 2) = nr_grant_frames(gt); + fastabi_value_n(regs, 3) = gt->max_grant_frames; + grant_read_unlock(gt); + break; + } + case GNTTABOP_get_version: + { + struct grant_table *gt = current->domain->grant_table; + + fastabi_value_n(regs, 2) = gt->gt_version; + break; + } + case GNTTABOP_set_version: + { + gnttab_set_version_t op = { .version = fastabi_value_n(regs, 2) }; + rc = gnttab_set_version(&op); + break; + } + default: + rc = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = rc; +} +#endif + #ifdef CONFIG_COMPAT #include "compat/grant_table.c" #endif diff --git a/xen/common/kernel.c b/xen/common/kernel.c index eff6db6c8f..2230ccdcaf 100644 --- a/xen/common/kernel.c +++ b/xen/common/kernel.c @@ -18,6 +18,10 @@ #include <asm/current.h> #include <public/version.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_COMPAT #include <compat/version.h> @@ -772,6 +776,35 @@ long do_xen_version(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return -ENOSYS; } +#ifdef CONFIG_FASTABI +void do_xen_version_fast_op(struct cpu_user_regs *regs) +{ + long cmd = fastabi_value_n(regs, 1); + long rc = 0; + + switch ( cmd ) { + case XENVER_version: + rc = (xen_major_version() << 16) | xen_minor_version(); + break; + case XENVER_get_features: + { + uint32_t submap = 0, submap_idx = fastabi_value_n(regs, 2); + + rc = xenver_get_features(current->domain, submap_idx, &submap); + + if ( !rc ) + fastabi_value_n(regs, 3) = submap; + break; + } + default: + rc = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = rc; +} +#endif + /* * Local variables: * mode: C diff --git a/xen/common/memory.c b/xen/common/memory.c index 3688e6dd50..689218390e 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -35,6 +35,10 @@ #include <public/memory.h> #include <xsm/xsm.h> +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_X86 #include <asm/guest.h> #endif @@ -1864,6 +1868,112 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg) return rc; } +#ifdef CONFIG_FASTABI +void do_memory_fast_op(struct cpu_user_regs *regs) +{ + unsigned long cmd = fastabi_value_n(regs, 1); + unsigned long start_extent = cmd >> MEMOP_EXTENT_SHIFT; + long rc; + int op = cmd & MEMOP_CMD_MASK; + + switch ( op ) { + case XENMEM_add_to_physmap: + { + struct xen_add_to_physmap xatp = { + .size = fastabi_value_n(regs, 2), + .space = fastabi_value_n(regs, 3), + .idx = fastabi_value_n(regs, 4), + .gpfn = fastabi_value_n(regs, 5) + }; + + BUILD_BUG_ON((typeof(xatp.size))-1 > (UINT_MAX >> MEMOP_EXTENT_SHIFT)); + + /* Check for malicious or buggy input. */ + if ( start_extent != (typeof(xatp.size))start_extent ) + { + rc = -EDOM; + break; + } + + /* Foreign mapping is only possible via add_to_physmap_batch. */ + if ( xatp.space == XENMAPSPACE_gmfn_foreign ) + { + rc = -ENOSYS; + break; + } + + rc = xatp_permission_check(current->domain, xatp.space); + if ( rc ) + break; + + rc = xenmem_add_to_physmap(current->domain, &xatp, start_extent); + + if ( xatp.space == XENMAPSPACE_gmfn_range && rc > 0 ) + panic("TODO"); + //rc = hypercall_create_continuation( + // __HYPERVISOR_memory_op, "lh", + // op | (rc << MEMOP_EXTENT_SHIFT), arg); + break; + } + + case XENMEM_remove_from_physmap: + { + unsigned long gpfn = fastabi_value_n(regs, 5); + struct page_info *page; + + if ( unlikely(start_extent) ) + { + rc = -EINVAL; + break; + } + + if ( !paging_mode_translate(current->domain) ) + { + rc = -EACCES; + break; + } + + page = get_page_from_gfn(current->domain, gpfn, NULL, P2M_ALLOC); + if ( page ) + { + rc = guest_physmap_remove_page(current->domain, _gfn(gpfn), + page_to_mfn(page), 0); + put_page(page); + } + else + rc = -ENOENT; + + break; + } + + case XENMEM_memory_map: + { + struct domain *d = current->domain; + unsigned long nr_entries = fastabi_value_n(regs, 2); + paddr_t buffer_addr = fastabi_value_n(regs, 3); + + spin_lock(&d->arch.e820_lock); + + if ( nr_entries > d->arch.nr_e820 ) + nr_entries = d->arch.nr_e820; + + if ( hvm_copy_to_guest_phys(buffer_addr, d->arch.e820, + nr_entries * sizeof(struct e820entry), current) ) + rc = -EFAULT; + + spin_unlock(&d->arch.e820_lock); + break; + } + + default: + rc = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = rc; +} +#endif + void clear_domain_page(mfn_t mfn) { void *ptr = map_domain_page(mfn); diff --git a/xen/common/sched/core.c b/xen/common/sched/core.c index b2c784c60e..51b2fbc00a 100644 --- a/xen/common/sched/core.c +++ b/xen/common/sched/core.c @@ -41,6 +41,10 @@ #include "private.h" +#ifdef CONFIG_FASTABI +#include <xen/fastabi.h> +#endif + #ifdef CONFIG_XEN_GUEST #include <asm/guest.h> #else @@ -1896,6 +1900,110 @@ void domain_update_node_aff(struct domain *d, struct affinity_masks *affinity) typedef long ret_t; +#ifdef CONFIG_FASTABI +void do_sched_fast_op(struct cpu_user_regs *regs) +{ + long ret = 0; + unsigned long cmd = fastabi_value_n(regs, 1); + + switch ( cmd ) + { + case SCHEDOP_yield: + { + ret = vcpu_yield(); + break; + } + + case SCHEDOP_block: + { + vcpu_block_enable_events(); + break; + } + + case SCHEDOP_shutdown: + { + struct sched_shutdown sched_shutdown = { + .reason = fastabi_value_n(regs, 2) + }; + + TRACE_TIME(TRC_SCHED_SHUTDOWN, current->domain->domain_id, + current->vcpu_id, sched_shutdown.reason); + ret = domain_shutdown(current->domain, (u8)sched_shutdown.reason); + + break; + } + + case SCHEDOP_shutdown_code: + { + struct sched_shutdown sched_shutdown = { + .reason = fastabi_value_n(regs, 2) + }; + struct domain *d = current->domain; + + TRACE_TIME(TRC_SCHED_SHUTDOWN_CODE, d->domain_id, current->vcpu_id, + sched_shutdown.reason); + + spin_lock(&d->shutdown_lock); + if ( d->shutdown_code == SHUTDOWN_CODE_INVALID ) + d->shutdown_code = (u8)sched_shutdown.reason; + spin_unlock(&d->shutdown_lock); + + ret = 0; + break; + } + + case SCHEDOP_poll: + { + uint64_t timeout = fastabi_value_n(regs, 2); + evtchn_port_t port = fastabi_value_n(regs, 3); + + ret = vcpu_poll(1, timeout, &port); + + break; + } + + case SCHEDOP_watchdog: + { + struct sched_watchdog sched_watchdog = { + .id = fastabi_value_n(regs, 2), + .timeout = fastabi_value_n(regs, 3) + }; + + ret = domain_watchdog( + current->domain, sched_watchdog.id, sched_watchdog.timeout); + break; + } + + case SCHEDOP_pin_override: + { + struct sched_pin_override sched_pin_override = { + .pcpu = fastabi_value_n(regs, 2), + }; + unsigned int cpu; + + ret = -EPERM; + if ( !is_hardware_domain(current->domain) ) + break; + + ret = -EINVAL; + if ( sched_pin_override.pcpu >= NR_CPUS ) + break; + + cpu = sched_pin_override.pcpu < 0 ? NR_CPUS : sched_pin_override.pcpu; + ret = vcpu_temporary_affinity(current, cpu, VCPU_AFFINITY_OVERRIDE); + + break; + } + + default: + ret = -ENOSYS; + break; + } + + fastabi_value_n(regs, 0) = ret; +} +#endif + #endif /* !COMPAT */ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) @@ -1961,7 +2069,6 @@ ret_t do_sched_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg) break; ret = do_poll(&sched_poll); - break; } diff --git a/xen/include/public/event_channel.h b/xen/include/public/event_channel.h index c5548d206c..969c9ec264 100644 --- a/xen/include/public/event_channel.h +++ b/xen/include/public/event_channel.h @@ -208,10 +208,17 @@ struct evtchn_status { } unbound; /* EVTCHNSTAT_unbound */ struct { domid_t dom; + uint16_t _pad; evtchn_port_t port; } interdomain; /* EVTCHNSTAT_interdomain */ uint32_t pirq; /* EVTCHNSTAT_pirq */ uint32_t virq; /* EVTCHNSTAT_virq */ +#ifndef __XEN__ + struct { + uint32_t _output1; + uint32_t _output2; + }; +#endif } u; }; typedef struct evtchn_status evtchn_status_t; diff --git a/xen/include/public/fastabi.h b/xen/include/public/fastabi.h new file mode 100644 index 0000000000..51f5085ce6 --- /dev/null +++ b/xen/include/public/fastabi.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: MIT */ +#ifndef __XEN_PUBLIC_FASTABI_H__ +#define __XEN_PUBLIC_FASTABI_H__ + +#if defined(__x86_64__) +#define __HYPERVISOR_FASTABI_MASK 0x40000000U + +enum xen_hypercall_vendor { + Intel, + Amd +}; +#else +#define __HYPERVISOR_FASTABI_MASK 0 + +enum xen_hypercall_vendor { + Native +}; +#endif + +#endif diff --git a/xen/include/xen/fastabi.h b/xen/include/xen/fastabi.h new file mode 100644 index 0000000000..83ede943e0 --- /dev/null +++ b/xen/include/xen/fastabi.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef XEN_FASTABI_H +#define XEN_FASTABI_H + +#include <asm/fastabi.h> + +void fastabi_dispatch(unsigned long index, struct cpu_user_regs *regs); +void fastabi_make_continuation(void); + +void do_event_channel_fast_op(struct cpu_user_regs *regs); + +long common_vcpu_fast_op(struct cpu_user_regs *regs, int cmd, struct vcpu *v); +void do_vcpu_fast_op(struct cpu_user_regs *regs); +void do_hvm_fast_op(struct cpu_user_regs *regs); +void do_memory_fast_op(struct cpu_user_regs *regs); +void do_grant_table_fast_op(struct cpu_user_regs *regs); +void do_sched_fast_op(struct cpu_user_regs *regs); +void do_xen_version_fast_op(struct cpu_user_regs *regs); + +#endif /* XEN_FASTABI_H */ \ No newline at end of file -- 2.50.1 Teddy Astie | Vates XCP-ng Developer XCP-ng & Xen Orchestra - Vates solutions web: https://vates.tech