Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions mk/config.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make ELFUSE_NR_EMBEDDER_HVC6= lets an empty value override ?=, then CFLAGS picks up -DELFUSE_NR_EMBEDDER_HVC6= and the C hook becomes if (nr == ) -- syntax error. Either skip the -D when the value is empty, or guard the C side with a numeric check:

#if defined(ELFUSE_NR_EMBEDDER_HVC6) && (ELFUSE_NR_EMBEDDER_HVC6 + 0 > 0)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure make ELFUSE_NR_EMBEDDER_HVC6= will disable this variable

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @jserv ,

Please check if I added block code below can prevent the issue you said.

ifneq ($(strip $(ELFUSE_NR_EMBEDDER_HVC6)),)
CFLAGS += -DELFUSE_NR_EMBEDDER_HVC6=$(ELFUSE_NR_EMBEDDER_HVC6)
endif


# 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)
Expand Down Expand Up @@ -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
9 changes: 8 additions & 1 deletion src/core/guest.h
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,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.
Expand Down
37 changes: 37 additions & 0 deletions src/syscall/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,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;
Expand Down Expand Up @@ -1888,6 +1894,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);
Expand Down
Loading