Skip to content

Commit 5d8954b

Browse files
authored
Merge pull request #1129 from AntelopeIO/fsgsbase
enable `fsgsbase` instructions on Linux 5.9+ for EOS VM OC
2 parents 10a0ecb + 3d00b02 commit 5d8954b

File tree

7 files changed

+91
-10
lines changed

7 files changed

+91
-10
lines changed

.github/workflows/build.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,9 @@ jobs:
168168
path: /cores
169169
compression-level: 0
170170
- name: Check CPU Features
171-
run: awk 'BEGIN {err = 1} /bmi2/ && /adx/ {err = 0} END {exit err}' /proc/cpuinfo
171+
run: |
172+
awk 'BEGIN {err = 1} /bmi2/ && /adx/ {err = 0} END {exit err}' /proc/cpuinfo
173+
build/tools/fsgsbase-enabled
172174
173175
np-tests:
174176
name: NP Tests (${{matrix.cfg.name}})

libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/gs_seg_helpers.h

+2
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ int32_t eos_vm_oc_grow_memory(int32_t grow, int32_t max);
2626
sigjmp_buf* eos_vm_oc_get_jmp_buf();
2727
void* eos_vm_oc_get_exception_ptr();
2828
void* eos_vm_oc_get_bounce_buffer_list();
29+
uint64_t eos_vm_oc_getgs();
30+
void eos_vm_oc_setgs(uint64_t gs);
2931

3032
#ifdef __cplusplus
3133
}

libraries/chain/webassembly/runtimes/eos-vm-oc/executor.cpp

+5-6
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ static void segv_handler(int sig, siginfo_t* info, void* ctx) {
3939
control_block* cb_in_main_segment;
4040

4141
//a 0 GS value is an indicator an executor hasn't been active on this thread recently
42-
uint64_t current_gs;
43-
syscall(SYS_arch_prctl, ARCH_GET_GS, &current_gs);
44-
if(current_gs == 0)
42+
uint64_t current_gs = eos_vm_oc_getgs();
43+
if(eos_vm_oc_getgs() == 0)
4544
goto notus;
4645

4746
cb_in_main_segment = reinterpret_cast<control_block*>(current_gs - memory::cb_offset);
@@ -170,11 +169,11 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
170169
mprotect(mem.full_page_memory_base() + initial_page_offset * eosio::chain::wasm_constraints::wasm_page_size,
171170
(code.starting_memory_pages - initial_page_offset) * eosio::chain::wasm_constraints::wasm_page_size, PROT_READ | PROT_WRITE);
172171
}
173-
arch_prctl(ARCH_SET_GS, (unsigned long*)(mem.zero_page_memory_base()+initial_page_offset*memory::stride));
172+
eos_vm_oc_setgs((uint64_t)mem.zero_page_memory_base()+initial_page_offset*memory::stride);
174173
memset(mem.full_page_memory_base(), 0, 64u*1024u*code.starting_memory_pages);
175174
}
176175
else
177-
arch_prctl(ARCH_SET_GS, (unsigned long*)mem.zero_page_memory_base());
176+
eos_vm_oc_setgs((uint64_t)mem.zero_page_memory_base());
178177

179178
void* globals;
180179
if(code.initdata_prologue_size > memory::max_prologue_size) {
@@ -261,7 +260,7 @@ void executor::execute(const code_descriptor& code, memory& mem, apply_context&
261260
}
262261

263262
executor::~executor() {
264-
arch_prctl(ARCH_SET_GS, nullptr);
263+
eos_vm_oc_setgs(0);
265264
munmap(code_mapping, code_mapping_size);
266265
}
267266

libraries/chain/webassembly/runtimes/eos-vm-oc/gs_seg_helpers.c

+62-3
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
#include <asm/prctl.h>
44
#include <sys/prctl.h>
55
#include <sys/mman.h>
6+
#include <sys/auxv.h>
7+
#include <elf.h>
8+
#include <immintrin.h>
69

710
int arch_prctl(int code, unsigned long* addr);
811

12+
#ifndef HWCAP2_FSGSBASE
13+
#define HWCAP2_FSGSBASE (1 << 1)
14+
#endif
15+
916
#define EOSVMOC_MEMORY_PTR_cb_ptr GS_PTR struct eos_vm_oc_control_block* const cb_ptr = ((GS_PTR struct eos_vm_oc_control_block* const)(EOS_VM_OC_CONTROL_BLOCK_OFFSET));
1017

1118
int32_t eos_vm_oc_grow_memory(int32_t grow, int32_t max) {
@@ -37,10 +44,9 @@ int32_t eos_vm_oc_grow_memory(int32_t grow, int32_t max) {
3744
gs_diff = grow_amount;
3845
}
3946

40-
uint64_t current_gs;
41-
arch_prctl(ARCH_GET_GS, &current_gs);
47+
uint64_t current_gs = eos_vm_oc_getgs();
4248
current_gs += gs_diff * EOS_VM_OC_MEMORY_STRIDE;
43-
arch_prctl(ARCH_SET_GS, (unsigned long*)current_gs);
49+
eos_vm_oc_setgs(current_gs);
4450
cb_ptr->current_linear_memory_pages += grow_amount;
4551
cb_ptr->first_invalid_memory_address += grow_amount*64*1024;
4652

@@ -64,3 +70,56 @@ void* eos_vm_oc_get_bounce_buffer_list() {
6470
EOSVMOC_MEMORY_PTR_cb_ptr;
6571
return cb_ptr->bounce_buffers;
6672
}
73+
74+
uint64_t eos_vm_oc_getgs_syscall() {
75+
uint64_t gs;
76+
arch_prctl(ARCH_GET_GS, &gs);
77+
return gs;
78+
}
79+
80+
uint64_t __attribute__ ((__target__ ("fsgsbase"))) eos_vm_oc_getgs_fsgsbase() {
81+
return _readgsbase_u64();
82+
}
83+
84+
void eos_vm_oc_setgs_syscall(uint64_t gs) {
85+
arch_prctl(ARCH_SET_GS, (unsigned long*)gs); //cast to a (unsigned long*) to match local declaration above
86+
}
87+
88+
void __attribute__ ((__target__ ("fsgsbase"))) eos_vm_oc_setgs_fsgsbase(uint64_t gs) {
89+
return _writegsbase_u64(gs);
90+
}
91+
92+
extern char** _dl_argv;
93+
static int eos_vm_oc_use_fsgsbase() {
94+
/* ifunc resolvers run _super_ early -- before getenv() is set up even! This is relying on the layout of _dl_argv to be
95+
_dl_argv
96+
97+
argc, argv[0], ..., argv[argc - 1], NULL, evniron0, environ1, ..., NULL
98+
*/
99+
const int argc = *(int*)(_dl_argv - 1);
100+
char** my_environ = _dl_argv + argc + 1;
101+
while(*my_environ != NULL) {
102+
const char disable_str[] = "SPRING_DISABLE_FSGSBASE";
103+
if(strncmp(*my_environ++, disable_str, strlen(disable_str)) == 0)
104+
return 0;
105+
}
106+
107+
//see linux Documentation/arch/x86/x86_64/fsgs.rst; check that kernel has enabled userspace fsgsbase
108+
return getauxval(AT_HWCAP2) & HWCAP2_FSGSBASE;
109+
}
110+
111+
uint64_t (*resolve_eos_vm_oc_getgs())() {
112+
if(eos_vm_oc_use_fsgsbase())
113+
return eos_vm_oc_getgs_fsgsbase;
114+
return eos_vm_oc_getgs_syscall;
115+
}
116+
117+
uint64_t eos_vm_oc_getgs() __attribute__ ((ifunc ("resolve_eos_vm_oc_getgs")));
118+
119+
void (*resolve_eos_vm_oc_setgs())(uint64_t) {
120+
if(eos_vm_oc_use_fsgsbase())
121+
return eos_vm_oc_setgs_fsgsbase;
122+
return eos_vm_oc_setgs_syscall;
123+
}
124+
125+
void eos_vm_oc_setgs(uint64_t) __attribute__ ((ifunc ("resolve_eos_vm_oc_setgs")));

tools/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/llvm-gcov.sh ${CMAKE_CURRENT_BINARY_D
22
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ctestwrapper.sh ${CMAKE_CURRENT_BINARY_DIR}/ctestwrapper.sh COPYONLY)
33
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/validate_reflection.py ${CMAKE_CURRENT_BINARY_DIR}/validate_reflection.py COPYONLY)
44
configure_file(net-util.py net-util.py COPYONLY)
5+
6+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
7+
add_executable(fsgsbase-enabled fsgsbase-enabled.c)
8+
endif()

tools/fsgsbase-enabled.c

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <sys/auxv.h>
2+
#include <elf.h>
3+
4+
#ifndef HWCAP2_FSGSBASE
5+
#define HWCAP2_FSGSBASE (1 << 1)
6+
#endif
7+
8+
int main() {
9+
return !(getauxval(AT_HWCAP2) & HWCAP2_FSGSBASE);
10+
}

unittests/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ foreach(TEST_SUITE ${UNIT_TESTS}) # create an independent target for each test s
9797
# to run unit_test with all log from blockchain displayed, put "--verbose" after "--", i.e. "unit_test -- --verbose"
9898
foreach(RUNTIME ${EOSIO_WASM_RUNTIMES})
9999
add_test(NAME ${TRIMMED_SUITE_NAME}_unit_test_${RUNTIME} COMMAND unit_test --run_test=${SUITE_NAME} --report_level=detailed --color_output -- --${RUNTIME})
100+
# add a duplicate test to run without fsgsbase instructions for a limited number of OC wasm tests
101+
if(RUNTIME STREQUAL "eos-vm-oc" AND TRIMMED_SUITE_NAME MATCHES "^wasm_part")
102+
add_test(NAME ${TRIMMED_SUITE_NAME}_unit_test_${RUNTIME}-nofsgs COMMAND unit_test --run_test=${SUITE_NAME} --report_level=detailed --color_output -- --${RUNTIME})
103+
set_tests_properties(${TRIMMED_SUITE_NAME}_unit_test_${RUNTIME}-nofsgs PROPERTIES ENVIRONMENT "SPRING_DISABLE_FSGSBASE=1" COST 5000)
104+
endif()
100105
# build list of tests to run during coverage testing
101106
if(ctest_tests)
102107
string(APPEND ctest_tests "|")

0 commit comments

Comments
 (0)