From 9e70e83ca99260e92225fc0088420ad902c6d8b5 Mon Sep 17 00:00:00 2001 From: Trung Date: Thu, 4 Jun 2026 22:06:25 +0700 Subject: [PATCH] Add translated embedder syscall hook Translated x86_64 guests cannot issue the AArch64 HVC instruction used by the existing embedder extension ABI. This prevents those guests from using embedder-provided services such as the graphics bridge. Add a private elfuse pseudo-syscall as the translated guest counterpart to HVC 6. The syscall keeps the existing hvc6_handler ABI instead of adding a second embedder callback path, so native and translated guests can share the same dispatch logic. The pseudo-syscall is enabled through the build system and is gated on g->is_rosetta so native AArch64 guests cannot reach the embedder hook through SVC. The selected number is required to remain outside syscall_table; the build fails if it would collide with the generated Linux syscall table. --- mk/config.mk | 8 ++++++++ src/core/guest.h | 9 ++++++++- src/syscall/syscall.c | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/mk/config.mk b/mk/config.mk index 7270e28..5daacd3 100644 --- a/mk/config.mk +++ b/mk/config.mk @@ -6,6 +6,10 @@ BUILD_DIR := build ELFUSE_BIN := $(BUILD_DIR)/elfuse VERSION ?= $(shell git describe --tags --always --dirty 2>/dev/null || echo "unknown") +# Private pseudo-syscall number used by translated guests to invoke the +# embedder HVC 6 hook. This is not a Linux syscall number. +ELFUSE_NR_EMBEDDER_HVC6 ?= 999 + # Test binary directory: either pre-built via GUEST_TEST_BINARIES, # auto-detected from build/bin, or locally cross-compiled via $(CROSS_COMPILE)gcc. ifeq ($(origin GUEST_TEST_BINARIES), undefined) @@ -51,3 +55,7 @@ CFLAGS := -O2 -Wall -Wextra -Wpedantic \ -Wshadow -Wstrict-prototypes -Wmissing-prototypes \ -Wformat=2 -Wimplicit-fallthrough -Wundef \ -Wnull-dereference -Wno-unused-parameter + +ifneq ($(strip $(ELFUSE_NR_EMBEDDER_HVC6)),) +CFLAGS += -DELFUSE_NR_EMBEDDER_HVC6=$(ELFUSE_NR_EMBEDDER_HVC6) +endif diff --git a/src/core/guest.h b/src/core/guest.h index 9e40ae3..a2094a6 100644 --- a/src/core/guest.h +++ b/src/core/guest.h @@ -490,7 +490,14 @@ typedef struct { _Atomic uint64_t pt_gen; /* - * Optional HVC #6 embedder extension hook. + * Optional HVC 6 embedder extension hook. + * + * Native AArch64 guests reach this through HVC 6. When the build enables + * ELFUSE_NR_EMBEDDER_HVC6, translated Rosetta guests may reach the same + * handler through a private pseudo-syscall gated on g->is_rosetta. + * + * Handler implementations must treat call_nr and args as untrusted guest + * input and allowlist supported call numbers. * * The handler may be invoked concurrently from multiple host threads once * the guest becomes multi-threaded, so implementations must be thread-safe. diff --git a/src/syscall/syscall.c b/src/syscall/syscall.c index 3b67e2d..6ae0e20 100644 --- a/src/syscall/syscall.c +++ b/src/syscall/syscall.c @@ -1641,6 +1641,12 @@ static int64_t sc_futex_waitv(guest_t *g, #error "SC_TABLE_SIZE must exceed SC_MAX_SYSCALL_NUM" #endif +#if defined(ELFUSE_NR_EMBEDDER_HVC6) && (ELFUSE_NR_EMBEDDER_HVC6 + 0 > 0) +_Static_assert(ELFUSE_NR_EMBEDDER_HVC6 > SC_TABLE_SIZE, + "ELFUSE_NR_EMBEDDER_HVC6 must be outside syscall_table"); +#define ELFUSE_ROSETTA_EMBEDDER_SYSCALL 1 +#endif + typedef struct { syscall_handler_t handler; bool needs_extra_regs; @@ -1818,6 +1824,37 @@ int syscall_dispatch(hv_vcpu_t vcpu, guest_t *g, int *exit_code, bool verbose) slow_path: entry = RANGE_CHECK(nr, 0, SC_TABLE_SIZE) ? &syscall_table[nr] : NULL; +/* + * Private embedder pseudo-syscall for translated guests. + * + * This is not a Linux syscall number. Translated x86_64 guests cannot + * issue native AArch64 HVC instructions, so elfuse uses this private + * build-selected syscall number as the translated counterpart to HVC 6. + * + * This path is gated on g->is_rosetta so native AArch64 guests cannot + * reach the embedder hook through SVC. + * + * Layout: + * x8 = ELFUSE_ROSETTA_EMBEDDER_SYSCALL + * x0 = embedder call number + * x1 = guest virtual address of uint64_t args[8] + */ +#ifdef ELFUSE_ROSETTA_EMBEDDER_SYSCALL + if (g->is_rosetta && nr == ELFUSE_NR_EMBEDDER_HVC6 && g->hvc6_handler) { + uint64_t call_nr = 0; + uint64_t args_gva = 0; + hv_vcpu_get_reg(vcpu, HV_REG_X0, &call_nr); + hv_vcpu_get_reg(vcpu, HV_REG_X1, &args_gva); + uint64_t guest_args[8] = {0}; + if (guest_read_small(g, args_gva, guest_args, sizeof(guest_args)) < 0) { + result = -LINUX_EFAULT; + } else { + result = g->hvc6_handler(call_nr, guest_args, g->hvc6_userdata); + } + goto fast_done; + } +#endif + hv_vcpu_get_reg(vcpu, HV_REG_X0, &x0); hv_vcpu_get_reg(vcpu, HV_REG_X1, &x1); hv_vcpu_get_reg(vcpu, HV_REG_X2, &x2);