:kernel: Fix stack alignment in syscall entry on x86_64.
The user iframe and associated data that the syscall entry pushes to the stack directly were causing the stack to be mis-aligned by 8 bytes. Since we re-aligned %rsp afterwards, for most usecases this wasn't a problem. However, since we stored the pre-realinged %rsp in %rbp (as we need it to access the iframe data), this also meant that anything which depended on %rbp being 16-byte-aligned would run into serious problems. As it turned out, GCC 7 assumed that %rbp was indeed 16-byte-aligned, and so optimized certain accesses to use SSE instructions that depended on this alignment. Since inside any callstack begining with a syscall this was not the case, a "General Protection Exception" resulted (see #14160 for an example) at the first usage of such an instruction. I wasn't really sure what was going on when it first came up, and so "fixed" it by disabling the GCC optimization that used such instructions. Replacing the -fdisable... with -mstackrealign thus also "fixes" the problem, as I discovered earlier today, as it forces GCC to realign the stack in function prologues. So instead of rounding %rsp down to the nearest aligned address after the pushes are complete, we offset %rsp by the amount the pushes are not, thus fixing both %rsp and %rbp in syscall handling routines. This of course depends on syscall_rsp being already aligned, which it is. Thanks to PulkoMandy and js for the advice and guidance (and PulkoMandy for the ASCII art), as this is essentially my first time working with kernel assembly.
This commit is contained in:
parent
77c8afb47f
commit
4a459f066d
@ -75,21 +75,6 @@ KernelMergeObject kernel_core.o :
|
||||
: $(TARGET_KERNEL_PIC_CCFLAGS)
|
||||
;
|
||||
|
||||
if $(HAIKU_GCC_VERSION_$(TARGET_PACKAGING_ARCH)[1]) >= 7
|
||||
&& ( $(TARGET_ARCH) = x86 || $(TARGET_ARCH) = x86_64 ) {
|
||||
# With the rtl-stv1 pass on these files, the kernel panics towards the end
|
||||
# of the boot process with a "General Protection Exception", see
|
||||
# https://dev.haiku-os.org/ticket/14160. The pass itself vectorizes
|
||||
# a significant number of otherwise-scalar operations, which may be why
|
||||
# disabling it fixes the problem.
|
||||
#
|
||||
# At time of writing, GCC does not seem to have a way to disable
|
||||
# vectorization as a result of optimization without disabling
|
||||
# FPU usage altogether, which of course is not what we want and
|
||||
# breaks when using libstdc++'s headers anyway.
|
||||
ObjectC++Flags commpage.o signal.o thread.o : -fdisable-rtl-stv1 ;
|
||||
}
|
||||
|
||||
# Generate the header defining macros for C++ structure sizes.
|
||||
local kernelC++StructSizesHeader = [ FGristFiles kernel_c++_struct_sizes.h ] ;
|
||||
TARGET_HDRS_$(TARGET_PACKAGING_ARCH) on $(kernelC++StructSizesHeader)
|
||||
|
@ -343,6 +343,9 @@ FUNCTION(x86_64_syscall_entry):
|
||||
movq %rsp, %gs:ARCH_THREAD_user_rsp
|
||||
movq %gs:ARCH_THREAD_syscall_rsp, %rsp
|
||||
|
||||
// The following pushes de-align the stack by 8 bytes, so account for that first.
|
||||
sub $8, %rsp
|
||||
|
||||
// Set up an iframe on the stack (R11 = saved RFLAGS, RCX = saved RIP).
|
||||
push $USER_DATA_SELECTOR // ss
|
||||
push %gs:ARCH_THREAD_user_rsp // rsp
|
||||
@ -357,7 +360,6 @@ FUNCTION(x86_64_syscall_entry):
|
||||
|
||||
// Frame pointer is the iframe.
|
||||
movq %rsp, %rbp
|
||||
andq $~15, %rsp
|
||||
|
||||
// Preserve call number (R14 is callee-save), get thread pointer.
|
||||
movq %rax, %r14
|
||||
|
Loading…
x
Reference in New Issue
Block a user