diff options
author | Matt Barden <mbarden@tintri.com> | 2021-02-10 16:38:21 -0500 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2021-03-12 14:31:59 -0500 |
commit | 915894ef19890baaed00080f85f6b69e225cda98 (patch) | |
tree | be6a9fd4fc57e6d3c668c133d26e8bf477dee226 | |
parent | b8ccc4133d4adaea81b30537c9a156ae726b2146 (diff) | |
download | illumos-joyent-915894ef19890baaed00080f85f6b69e225cda98.tar.gz |
13508 door_layout() should align the stack to 16 bytes for i386 processes
Reviewed by: Robert Mustacchi <rm+illumos@fingolfin.org>
Reviewed by: Andy Fiddaman <andy@omniosce.org>
Reviewed by: Gordon Ross <gordon.ross@tintri.com>
Approved by: Dan McDonald <danmcd@joyent.com>
-rw-r--r-- | usr/src/lib/libc/i386/sys/door.s | 10 | ||||
-rw-r--r-- | usr/src/pkg/manifests/system-test-ostest.mf | 4 | ||||
-rw-r--r-- | usr/src/test/os-tests/runfiles/default.run | 4 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/Makefile | 2 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/stackalign/Makefile | 78 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/stackalign/stack_amd64.s | 69 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/stackalign/stack_i386.s | 75 | ||||
-rw-r--r-- | usr/src/test/os-tests/tests/stackalign/stackalign.c | 170 | ||||
-rw-r--r-- | usr/src/uts/common/fs/doorfs/door_sys.c | 14 |
9 files changed, 424 insertions, 2 deletions
diff --git a/usr/src/lib/libc/i386/sys/door.s b/usr/src/lib/libc/i386/sys/door.s index 1e5561c387..d0785af1bc 100644 --- a/usr/src/lib/libc/i386/sys/door.s +++ b/usr/src/lib/libc/i386/sys/door.s @@ -22,6 +22,8 @@ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. + * + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. */ .file "door.s" @@ -110,7 +112,7 @@ /* * int * __door_return( - * void *data_ptr, + * void *data_ptr, * size_t data_size, (in bytes) * door_return_desc_t *door_ptr, (holds returned desc info) * caddr_t stack_base, @@ -142,6 +144,8 @@ door_restart: * data (if any) * sp-> struct door_results * + * The stack will be aligned to 16 bytes; we must maintain that + * alignment prior to any call instruction. * struct door_results has the arguments in place for the server proc, * so we just call it directly. */ @@ -152,14 +156,16 @@ door_restart: * this is the last server thread - call creation func for more */ movl DOOR_INFO_PTR(%esp), %eax + subl $12, %esp pushl %eax /* door_info_t * */ call door_depletion_cb@PLT - addl $4, %esp + addl $16, %esp 1: /* Call the door server function now */ movl DOOR_PC(%esp), %eax call *%eax /* Exit the thread if we return here */ + subl $12, %esp pushl $0 call _thrp_terminate /* NOTREACHED */ diff --git a/usr/src/pkg/manifests/system-test-ostest.mf b/usr/src/pkg/manifests/system-test-ostest.mf index e65c7b654f..596c19fb5d 100644 --- a/usr/src/pkg/manifests/system-test-ostest.mf +++ b/usr/src/pkg/manifests/system-test-ostest.mf @@ -14,6 +14,7 @@ # Copyright 2014, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2020 Joyent, Inc. # Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2021 Tintri by DDN, Inc. All rights reserved. # set name=pkg.fmri value=pkg:/system/test/ostest@$(PKGVERS) @@ -38,6 +39,7 @@ dir path=opt/os-tests/tests/sdevfs dir path=opt/os-tests/tests/secflags dir path=opt/os-tests/tests/sigqueue dir path=opt/os-tests/tests/sockfs +dir path=opt/os-tests/tests/stackalign dir path=opt/os-tests/tests/stress dir path=opt/os-tests/tests/syscall dir path=opt/os-tests/tests/timer @@ -110,6 +112,8 @@ file path=opt/os-tests/tests/sockfs/rights.32 mode=0555 file path=opt/os-tests/tests/sockfs/rights.64 mode=0555 file path=opt/os-tests/tests/sockfs/sockpair mode=0555 file path=opt/os-tests/tests/spoof-ras mode=0555 +file path=opt/os-tests/tests/stackalign/stackalign.32 mode=0555 +file path=opt/os-tests/tests/stackalign/stackalign.64 mode=0555 file path=opt/os-tests/tests/stress/dladm-kstat mode=0555 file path=opt/os-tests/tests/syscall/open.32 mode=0555 file path=opt/os-tests/tests/syscall/open.64 mode=0555 diff --git a/usr/src/test/os-tests/runfiles/default.run b/usr/src/test/os-tests/runfiles/default.run index 0370c425a9..e7b44684db 100644 --- a/usr/src/test/os-tests/runfiles/default.run +++ b/usr/src/test/os-tests/runfiles/default.run @@ -13,6 +13,7 @@ # Copyright (c) 2012 by Delphix. All rights reserved. # Copyright 2020 Joyent, Inc. # Copyright 2020 OmniOS Community Edition (OmniOSce) Association. +# Copyright 2021 Tintri by DDN, Inc. All rights reserved. # [DEFAULT] @@ -116,3 +117,6 @@ pre = ksensor_init tests = [ 'ksensor_basic.32','ksensor_basic.64', 'ksensor_err.32', 'ksensor_err.64' ] post = ksensor_fini + +[/opt/os-tests/tests/stackalign] +tests = ['stackalign.32', 'stackalign.64'] diff --git a/usr/src/test/os-tests/tests/Makefile b/usr/src/test/os-tests/tests/Makefile index c9f3391576..2783408243 100644 --- a/usr/src/test/os-tests/tests/Makefile +++ b/usr/src/test/os-tests/tests/Makefile @@ -12,6 +12,7 @@ # # Copyright (c) 2012, 2016 by Delphix. All rights reserved. # Copyright 2020 Joyent, Inc. +# Copyright 2021 Tintri by DDN, Inc. All rights reserved. # SUBDIRS_i386 = i386 imc @@ -28,6 +29,7 @@ SUBDIRS = \ sigqueue \ sockfs \ spoof-ras \ + stackalign \ stress \ syscall \ timer \ diff --git a/usr/src/test/os-tests/tests/stackalign/Makefile b/usr/src/test/os-tests/tests/stackalign/Makefile new file mode 100644 index 0000000000..4af7cb7352 --- /dev/null +++ b/usr/src/test/os-tests/tests/stackalign/Makefile @@ -0,0 +1,78 @@ +# +# This file and its contents are supplied under the terms of the +# Common Development and Distribution License ("CDDL"), version 1.0. +# You may only use this file in accordance with the terms of version +# 1.0 of the CDDL. +# +# A full copy of the text of the CDDL should have accompanied this +# source. A copy of the CDDL is also available via the Internet at +# http://www.illumos.org/license/CDDL. +# + +# +# Copyright 2020 Oxide Computer Company +# Copyright 2021 Tintri by DDN, Inc. All rights reserved. +# + +PROGS = stackalign + +PROGS32 = $(PROGS:%=%.32) +PROGS64 = $(PROGS:%=%.64) + +OBJS = $(PROGS32:%=%.o) $(PROGS64:%=%.o) +$(INTEL_BLD)OBJS += stack_i386.o stack_amd64.o + +ROOTOPTDIR = $(ROOT)/opt/os-tests/tests +ROOTOPTSTACK = $(ROOTOPTDIR)/stackalign +ROOTOPTPROGS = $(PROGS32:%=$(ROOTOPTSTACK)/%) $(PROGS64:%=$(ROOTOPTSTACK)/%) + +include $(SRC)/cmd/Makefile.cmd + +ASFLAGS += -P -D_ASM +CFLAGS += -D_REENTRANT +$(INTEL_BLD)LDFLAGS += -Wl,-zinitarray=get_stack_at_init + +.KEEP_STATE: + +all: $(PROGS32) $(PROGS64) + +install: $(ROOTOPTPROGS) + +clean: + -$(RM) $(OBJS) + +$(ROOTOPTPROGS): $(PROGS32) $(PROGS64) $(ROOTOPTSTACK) + +$(ROOTOPTDIR): + $(INS.dir) + +$(ROOTOPTSTACK): $(ROOTOPTDIR) + $(INS.dir) + +$(ROOTOPTSTACK)/%: % + $(INS.file) + +%.64.o: %.c + $(COMPILE64.c) $< -o $@ + +%.32.o: %.c + $(COMPILE.c) $< -o $@ + +stack_$(MACH).o: stack_$(MACH).s + $(COMPILE.s) $< -o $@ + +stack_$(MACH64).o: stack_$(MACH64).s + $(COMPILE64.s) $< -o $@ + +%.64: %.64.o $(INTEL_BLD)stack_$(MACH64).o + $(LINK64.c) -o $@ $^ $(LDLIBS64) + $(POST_PROCESS) + +%.32: %.32.o $(INTEL_BLD)stack_$(MACH).o + $(LINK.c) -o $@ $^ $(LDLIBS) + $(POST_PROCESS) + +clobber: clean + $(RM) $(PROGS32) $(PROGS64) + +FRC: diff --git a/usr/src/test/os-tests/tests/stackalign/stack_amd64.s b/usr/src/test/os-tests/tests/stackalign/stack_amd64.s new file mode 100644 index 0000000000..7fb4be88e3 --- /dev/null +++ b/usr/src/test/os-tests/tests/stackalign/stack_amd64.s @@ -0,0 +1,69 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. + */ + +/* + * Get the stack at entry and call a function with it as an argument. + */ + + .file "stack_amd64.s" + +#include <sys/asm_linkage.h> + +/* + * void + * get_stack_at_entry(test_ctx_t *ctx) + * + * ctx+0 is void (*)(uintptr_t stack, char *text), + * and ctx+8 is the 'text' argument. + * + * Passes the stack pointer prior to the invoking call instruction + * to the specified function. + */ + ENTRY(get_stack_at_entry) + pushq %rbp + movq %rsp, %rbp + movq %rdi, %rax + leaq 16(%rbp), %rdi + movq 8(%rax), %rsi + call *(%rax) + popq %rbp + ret + SET_SIZE(get_stack_at_entry) + +/* + * void + * get_stack_at_init(void) + * + * Passes the stack pointer prior to the invoking call instruction + * to initarray() (defined elsewhere). + * Tests alignment in section .init_array. + */ + ENTRY(get_stack_at_init) + pushq %rbp + movq %rsp, %rbp + leaq 16(%rbp), %rdi + call initarray@PLT + popq %rbp + ret + SET_SIZE(get_stack_at_init) + +/* + * Passes the stack pointer during init to initmain() (defined elsewhere). + * Tests alignment in section .init. + */ + .section ".init" + movq %rsp, %rdi + call initmain@PLT + diff --git a/usr/src/test/os-tests/tests/stackalign/stack_i386.s b/usr/src/test/os-tests/tests/stackalign/stack_i386.s new file mode 100644 index 0000000000..f8fb525cad --- /dev/null +++ b/usr/src/test/os-tests/tests/stackalign/stack_i386.s @@ -0,0 +1,75 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. + */ + +/* + * Get the stack at entry and call a function with it as an argument. + */ + + .file "stack_i386.s" + +#include <sys/asm_linkage.h> + +/* + * void + * get_stack_at_entry(test_ctx_t *ctx) + * + * ctx+0 is void (*)(uintptr_t stack, char *text), + * and ctx+4 is the 'text' argument. + * + * Passes the stack pointer prior to the invoking call instruction + * to the specified function. + */ + ENTRY(get_stack_at_entry) + pushl %ebp + movl %esp, %ebp + leal 8(%ebp), %eax + movl 8(%ebp), %ecx + pushl 4(%ecx) + pushl %eax + call *(%ecx) + addl $8, %esp + popl %ebp + ret + SET_SIZE(get_stack_at_entry) + +/* + * void + * get_stack_at_init(void) + * + * Passes the stack pointer prior to the invoking call instruction + * to initarray() (defined elsewhere). + * Tests alignment in section .init_array. + */ + ENTRY(get_stack_at_init) + pushl %ebp + movl %esp, %ebp + leal 8(%ebp), %eax + subl $8, %esp + movl %eax, (%esp) + call initarray@PLT + addl $8, %esp + popl %ebp + ret + SET_SIZE(get_stack_at_init) + +/* + * Passes the stack pointer during init to initmain() (defined elsewhere). + * Tests alignment in section .init. + */ + .section ".init" + movl %esp, %eax + pushl %eax + call initmain@PLT + addl $4, %esp diff --git a/usr/src/test/os-tests/tests/stackalign/stackalign.c b/usr/src/test/os-tests/tests/stackalign/stackalign.c new file mode 100644 index 0000000000..2ad77ea39d --- /dev/null +++ b/usr/src/test/os-tests/tests/stackalign/stackalign.c @@ -0,0 +1,170 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. + */ + +/* + * Test that the stack is aligned to expected values. + */ + +#include <stdio.h> +#include <pthread.h> +#include <thread.h> +#include <door.h> +#include <stdlib.h> +#include <unistd.h> +#include <ucontext.h> + +#include <sys/stack.h> + +/* + * The introduction of SSE led to the IA32 ABI changing the required stack + * alignment from 4 bytes to 16 bytes. Compilers assume this when using SSE. + */ +#if defined(__i386) +#undef STACK_ALIGN +#define STACK_ALIGN 16 +#endif + +#define ALIGN_ERR_IMPL(align, text) \ + "stack was not aligned to " #align " on " text "\n" +#define ALIGN_ERR_HELP(align, text) ALIGN_ERR_IMPL(align, text) +#define ALIGN_ERR(text) ALIGN_ERR_HELP(STACK_ALIGN, text) + +#define STACK_SIZE 16*1024 + +typedef struct test_ctx { + void (*func)(uintptr_t, char *); + char *text; +} test_ctx_t; + +extern void get_stack_at_entry(test_ctx_t *); + +void +teststack(uintptr_t stack, char *arg) +{ + if ((stack & (STACK_ALIGN - 1)) != 0) { + fprintf(stderr, ALIGN_ERR("%s"), (char *)arg); + exit(1); + } +} + +void +initmain(uintptr_t stack) +{ + teststack(stack, "section .init"); +} + +void +initarray(uintptr_t stack) +{ + teststack(stack, "section .init_array"); +} + +void +doorstack(uintptr_t stack, char *arg) +{ + teststack(stack, arg); + (void) door_return(NULL, 0, NULL, 0); +} + +char door_arg[] = "DOOR ARG"; + +int +main(int argc, char *argv[]) +{ + door_arg_t da = { + .data_ptr = (void *)door_arg, + .data_size = sizeof (door_arg) + }; + test_ctx_t arg = { + .func = teststack, + .text = "pthread_create()" + }; + ucontext_t back, uc; + pthread_t tid; + int door_fd, rc; + +#if defined(__sparc) + /* + * This hasn't been implemented for SPARC, so skip. + */ + fprintf(stderr, "No SPARC implementation of get_stack_at_entry\n"); + return (3); +#else + if (pthread_create(&tid, NULL, + (void *(*)(void *))get_stack_at_entry, &arg) != 0) { + perror("pthread_create() failed:"); + exit(-2); + } + (void) pthread_join(tid, NULL); + + arg.text = "thr_create()"; + + if (thr_create(NULL, 0, (void *(*)(void *))get_stack_at_entry, + &arg, 0, &tid) != 0) { + perror("thr_create() failed:"); + exit(-3); + } + (void) thr_join(tid, NULL, NULL); + + if (getcontext(&uc) < 0) { + perror("getcontext() failed"); + exit(-4); + } + + uc.uc_link = &back; + uc.uc_stack.ss_size = STACK_SIZE; + uc.uc_stack.ss_flags = 0; + if ((uc.uc_stack.ss_sp = malloc(STACK_SIZE)) == NULL) { + perror("failed to allocate stack"); + exit(-5); + } + + arg.text = "swapcontext()"; + makecontext(&uc, (void (*)(void *))get_stack_at_entry, 1, &arg); + if (swapcontext(&back, &uc) < 0) { + perror("swapcontext() failed"); + exit(-6); + } + + arg.func = doorstack; + arg.text = "door_call()"; + + if ((door_fd = door_create( + (door_server_procedure_t *)get_stack_at_entry, + &arg, 0)) < 0) { + perror("failed to create door"); + exit(-7); + } + + rc = door_call(door_fd, &da); + + if (rc < 0) { + perror("door call #1 failed"); + exit(-8); + } + + da.data_size += 5; + rc = door_call(door_fd, &da); + + if (rc < 0) { + perror("door call #2 failed"); + exit(-9); + } + + (void) close(door_fd); + + return (0); +#endif +} diff --git a/usr/src/uts/common/fs/doorfs/door_sys.c b/usr/src/uts/common/fs/doorfs/door_sys.c index 68a7a11d82..a2d3812938 100644 --- a/usr/src/uts/common/fs/doorfs/door_sys.c +++ b/usr/src/uts/common/fs/doorfs/door_sys.c @@ -22,6 +22,7 @@ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 by Delphix. All rights reserved. + * Copyright 2021 Tintri by DDN, Inc. All rights reserved. */ /* @@ -1114,6 +1115,19 @@ door_stack_copyout(const void *kaddr, void *uaddr, size_t count) } /* + * The IA32 ABI supplement 1.0 changed the required stack alignment to + * 16 bytes (from 4 bytes), so that code can make use of SSE instructions. + * This is already done for process entry, thread entry, and makecontext(); + * We need to do this for door_return as well. The stack will be aligned to + * whatever the door_results is aligned. + * See: usr/src/lib/libc/i386/gen/makectxt.c for more details. + */ +#if defined(__amd64) +#undef STACK_ALIGN32 +#define STACK_ALIGN32 16 +#endif + +/* * Writes the stack layout for door_return() into the door_server_t of the * server thread. */ |