1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
14  */
15 
16 /*
17  * Test that the stack is aligned to expected values.
18  */
19 
20 #include <stdio.h>
21 #include <pthread.h>
22 #include <thread.h>
23 #include <door.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <ucontext.h>
27 
28 #include <sys/stack.h>
29 
30 /*
31  * The introduction of SSE led to the IA32 ABI changing the required stack
32  * alignment from 4 bytes to 16 bytes. Compilers assume this when using SSE.
33  */
34 #if defined(__i386)
35 #undef STACK_ALIGN
36 #define	STACK_ALIGN 16
37 #endif
38 
39 #define	ALIGN_ERR_IMPL(align, text)				\
40 	"stack was not aligned to " #align " on " text "\n"
41 #define	ALIGN_ERR_HELP(align, text) ALIGN_ERR_IMPL(align, text)
42 #define	ALIGN_ERR(text) ALIGN_ERR_HELP(STACK_ALIGN, text)
43 
44 #define	STACK_SIZE 16*1024
45 
46 typedef struct test_ctx {
47 	void (*func)(uintptr_t, char *);
48 	char *text;
49 } test_ctx_t;
50 
51 extern void get_stack_at_entry(test_ctx_t *);
52 
53 void
teststack(uintptr_t stack,char * arg)54 teststack(uintptr_t stack, char *arg)
55 {
56 	if ((stack & (STACK_ALIGN - 1)) != 0) {
57 		fprintf(stderr, ALIGN_ERR("%s"), (char *)arg);
58 		exit(1);
59 	}
60 }
61 
62 void
initmain(uintptr_t stack)63 initmain(uintptr_t stack)
64 {
65 	teststack(stack, "section .init");
66 }
67 
68 void
initarray(uintptr_t stack)69 initarray(uintptr_t stack)
70 {
71 	teststack(stack, "section .init_array");
72 }
73 
74 void
doorstack(uintptr_t stack,char * arg)75 doorstack(uintptr_t stack, char *arg)
76 {
77 	teststack(stack, arg);
78 	(void) door_return(NULL, 0, NULL, 0);
79 }
80 
81 char door_arg[] = "DOOR ARG";
82 
83 int
main(int argc,char * argv[])84 main(int argc, char *argv[])
85 {
86 	door_arg_t da = {
87 	    .data_ptr = (void *)door_arg,
88 	    .data_size = sizeof (door_arg)
89 	};
90 	test_ctx_t arg = {
91 	    .func = teststack,
92 	    .text = "pthread_create()"
93 	};
94 	ucontext_t back, uc;
95 	pthread_t tid;
96 	int door_fd, rc;
97 
98 	if (pthread_create(&tid, NULL,
99 	    (void *(*)(void *))(uintptr_t)get_stack_at_entry, &arg) != 0) {
100 		perror("pthread_create() failed:");
101 		exit(-2);
102 	}
103 	(void) pthread_join(tid, NULL);
104 
105 	arg.text = "thr_create()";
106 
107 	if (thr_create(NULL, 0,
108 	    (void *(*)(void *))(uintptr_t)get_stack_at_entry,
109 	    &arg, 0, &tid) != 0) {
110 		perror("thr_create() failed:");
111 		exit(-3);
112 	}
113 	(void) thr_join(tid, NULL, NULL);
114 
115 	if (getcontext(&uc) < 0) {
116 		perror("getcontext() failed");
117 		exit(-4);
118 	}
119 
120 	uc.uc_link = &back;
121 	uc.uc_stack.ss_size = STACK_SIZE;
122 	uc.uc_stack.ss_flags = 0;
123 	if ((uc.uc_stack.ss_sp = malloc(STACK_SIZE)) == NULL) {
124 		perror("failed to allocate stack");
125 		exit(-5);
126 	}
127 
128 	arg.text = "swapcontext()";
129 	makecontext(&uc, (void (*)(void *))get_stack_at_entry, 1, &arg);
130 	if (swapcontext(&back, &uc) < 0) {
131 		perror("swapcontext() failed");
132 		exit(-6);
133 	}
134 
135 	arg.func = doorstack;
136 	arg.text = "door_call()";
137 
138 	if ((door_fd = door_create(
139 	    (door_server_procedure_t *)(uintptr_t)get_stack_at_entry,
140 	    &arg, 0)) < 0) {
141 		perror("failed to create door");
142 		exit(-7);
143 	}
144 
145 	rc = door_call(door_fd, &da);
146 
147 	if (rc < 0) {
148 		perror("door call #1 failed");
149 		exit(-8);
150 	}
151 
152 	da.data_size += 5;
153 	rc = door_call(door_fd, &da);
154 
155 	if (rc < 0) {
156 		perror("door call #2 failed");
157 		exit(-9);
158 	}
159 
160 	(void) close(door_fd);
161 
162 	return (0);
163 }
164