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