summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Barden <mbarden@tintri.com>2021-02-10 16:38:21 -0500
committerDan McDonald <danmcd@joyent.com>2021-03-12 14:31:59 -0500
commit915894ef19890baaed00080f85f6b69e225cda98 (patch)
treebe6a9fd4fc57e6d3c668c133d26e8bf477dee226
parentb8ccc4133d4adaea81b30537c9a156ae726b2146 (diff)
downloadillumos-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.s10
-rw-r--r--usr/src/pkg/manifests/system-test-ostest.mf4
-rw-r--r--usr/src/test/os-tests/runfiles/default.run4
-rw-r--r--usr/src/test/os-tests/tests/Makefile2
-rw-r--r--usr/src/test/os-tests/tests/stackalign/Makefile78
-rw-r--r--usr/src/test/os-tests/tests/stackalign/stack_amd64.s69
-rw-r--r--usr/src/test/os-tests/tests/stackalign/stack_i386.s75
-rw-r--r--usr/src/test/os-tests/tests/stackalign/stackalign.c170
-rw-r--r--usr/src/uts/common/fs/doorfs/door_sys.c14
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.
*/