1915894efSMatt Barden /*
2915894efSMatt Barden  * This file and its contents are supplied under the terms of the
3915894efSMatt Barden  * Common Development and Distribution License ("CDDL"), version 1.0.
4915894efSMatt Barden  * You may only use this file in accordance with the terms of version
5915894efSMatt Barden  * 1.0 of the CDDL.
6915894efSMatt Barden  *
7915894efSMatt Barden  * A full copy of the text of the CDDL should have accompanied this
8915894efSMatt Barden  * source.  A copy of the CDDL is also available via the Internet at
9915894efSMatt Barden  * http://www.illumos.org/license/CDDL.
10915894efSMatt Barden  */
11915894efSMatt Barden 
12915894efSMatt Barden /*
13915894efSMatt Barden  * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
14915894efSMatt Barden  */
15915894efSMatt Barden 
16915894efSMatt Barden /*
17915894efSMatt Barden  * Test that the stack is aligned to expected values.
18915894efSMatt Barden  */
19915894efSMatt Barden 
20915894efSMatt Barden #include <stdio.h>
21915894efSMatt Barden #include <pthread.h>
22915894efSMatt Barden #include <thread.h>
23915894efSMatt Barden #include <door.h>
24915894efSMatt Barden #include <stdlib.h>
25915894efSMatt Barden #include <unistd.h>
26915894efSMatt Barden #include <ucontext.h>
27915894efSMatt Barden 
28915894efSMatt Barden #include <sys/stack.h>
29915894efSMatt Barden 
30915894efSMatt Barden /*
31915894efSMatt Barden  * The introduction of SSE led to the IA32 ABI changing the required stack
32915894efSMatt Barden  * alignment from 4 bytes to 16 bytes. Compilers assume this when using SSE.
33915894efSMatt Barden  */
34915894efSMatt Barden #if defined(__i386)
35915894efSMatt Barden #undef STACK_ALIGN
36915894efSMatt Barden #define	STACK_ALIGN 16
37915894efSMatt Barden #endif
38915894efSMatt Barden 
39915894efSMatt Barden #define	ALIGN_ERR_IMPL(align, text)				\
40915894efSMatt Barden 	"stack was not aligned to " #align " on " text "\n"
41915894efSMatt Barden #define	ALIGN_ERR_HELP(align, text) ALIGN_ERR_IMPL(align, text)
42915894efSMatt Barden #define	ALIGN_ERR(text) ALIGN_ERR_HELP(STACK_ALIGN, text)
43915894efSMatt Barden 
44915894efSMatt Barden #define	STACK_SIZE 16*1024
45915894efSMatt Barden 
46915894efSMatt Barden typedef struct test_ctx {
47915894efSMatt Barden 	void (*func)(uintptr_t, char *);
48915894efSMatt Barden 	char *text;
49915894efSMatt Barden } test_ctx_t;
50915894efSMatt Barden 
51915894efSMatt Barden extern void get_stack_at_entry(test_ctx_t *);
52915894efSMatt Barden 
53915894efSMatt Barden void
teststack(uintptr_t stack,char * arg)54915894efSMatt Barden teststack(uintptr_t stack, char *arg)
55915894efSMatt Barden {
56915894efSMatt Barden 	if ((stack & (STACK_ALIGN - 1)) != 0) {
57915894efSMatt Barden 		fprintf(stderr, ALIGN_ERR("%s"), (char *)arg);
58915894efSMatt Barden 		exit(1);
59915894efSMatt Barden 	}
60915894efSMatt Barden }
61915894efSMatt Barden 
62915894efSMatt Barden void
initmain(uintptr_t stack)63915894efSMatt Barden initmain(uintptr_t stack)
64915894efSMatt Barden {
65915894efSMatt Barden 	teststack(stack, "section .init");
66915894efSMatt Barden }
67915894efSMatt Barden 
68915894efSMatt Barden void
initarray(uintptr_t stack)69915894efSMatt Barden initarray(uintptr_t stack)
70915894efSMatt Barden {
71915894efSMatt Barden 	teststack(stack, "section .init_array");
72915894efSMatt Barden }
73915894efSMatt Barden 
74915894efSMatt Barden void
doorstack(uintptr_t stack,char * arg)75915894efSMatt Barden doorstack(uintptr_t stack, char *arg)
76915894efSMatt Barden {
77915894efSMatt Barden 	teststack(stack, arg);
78915894efSMatt Barden 	(void) door_return(NULL, 0, NULL, 0);
79915894efSMatt Barden }
80915894efSMatt Barden 
81915894efSMatt Barden char door_arg[] = "DOOR ARG";
82915894efSMatt Barden 
83915894efSMatt Barden int
main(int argc,char * argv[])84915894efSMatt Barden main(int argc, char *argv[])
85915894efSMatt Barden {
86915894efSMatt Barden 	door_arg_t da = {
87915894efSMatt Barden 	    .data_ptr = (void *)door_arg,
88915894efSMatt Barden 	    .data_size = sizeof (door_arg)
89915894efSMatt Barden 	};
90915894efSMatt Barden 	test_ctx_t arg = {
91915894efSMatt Barden 	    .func = teststack,
92915894efSMatt Barden 	    .text = "pthread_create()"
93915894efSMatt Barden 	};
94915894efSMatt Barden 	ucontext_t back, uc;
95915894efSMatt Barden 	pthread_t tid;
96915894efSMatt Barden 	int door_fd, rc;
97915894efSMatt Barden 
98915894efSMatt Barden 	if (pthread_create(&tid, NULL,
99*3307fc5bSToomas Soome 	    (void *(*)(void *))(uintptr_t)get_stack_at_entry, &arg) != 0) {
100915894efSMatt Barden 		perror("pthread_create() failed:");
101915894efSMatt Barden 		exit(-2);
102915894efSMatt Barden 	}
103915894efSMatt Barden 	(void) pthread_join(tid, NULL);
104915894efSMatt Barden 
105915894efSMatt Barden 	arg.text = "thr_create()";
106915894efSMatt Barden 
107*3307fc5bSToomas Soome 	if (thr_create(NULL, 0,
108*3307fc5bSToomas Soome 	    (void *(*)(void *))(uintptr_t)get_stack_at_entry,
109915894efSMatt Barden 	    &arg, 0, &tid) != 0) {
110915894efSMatt Barden 		perror("thr_create() failed:");
111915894efSMatt Barden 		exit(-3);
112915894efSMatt Barden 	}
113915894efSMatt Barden 	(void) thr_join(tid, NULL, NULL);
114915894efSMatt Barden 
115915894efSMatt Barden 	if (getcontext(&uc) < 0) {
116915894efSMatt Barden 		perror("getcontext() failed");
117915894efSMatt Barden 		exit(-4);
118915894efSMatt Barden 	}
119915894efSMatt Barden 
120915894efSMatt Barden 	uc.uc_link = &back;
121915894efSMatt Barden 	uc.uc_stack.ss_size = STACK_SIZE;
122915894efSMatt Barden 	uc.uc_stack.ss_flags = 0;
123915894efSMatt Barden 	if ((uc.uc_stack.ss_sp = malloc(STACK_SIZE)) == NULL) {
124915894efSMatt Barden 		perror("failed to allocate stack");
125915894efSMatt Barden 		exit(-5);
126915894efSMatt Barden 	}
127915894efSMatt Barden 
128915894efSMatt Barden 	arg.text = "swapcontext()";
129915894efSMatt Barden 	makecontext(&uc, (void (*)(void *))get_stack_at_entry, 1, &arg);
130915894efSMatt Barden 	if (swapcontext(&back, &uc) < 0) {
131915894efSMatt Barden 		perror("swapcontext() failed");
132915894efSMatt Barden 		exit(-6);
133915894efSMatt Barden 	}
134915894efSMatt Barden 
135915894efSMatt Barden 	arg.func = doorstack;
136915894efSMatt Barden 	arg.text = "door_call()";
137915894efSMatt Barden 
138915894efSMatt Barden 	if ((door_fd = door_create(
139*3307fc5bSToomas Soome 	    (door_server_procedure_t *)(uintptr_t)get_stack_at_entry,
140915894efSMatt Barden 	    &arg, 0)) < 0) {
141915894efSMatt Barden 		perror("failed to create door");
142915894efSMatt Barden 		exit(-7);
143915894efSMatt Barden 	}
144915894efSMatt Barden 
145915894efSMatt Barden 	rc = door_call(door_fd, &da);
146915894efSMatt Barden 
147915894efSMatt Barden 	if (rc < 0) {
148915894efSMatt Barden 		perror("door call #1 failed");
149915894efSMatt Barden 		exit(-8);
150915894efSMatt Barden 	}
151915894efSMatt Barden 
152915894efSMatt Barden 	da.data_size += 5;
153915894efSMatt Barden 	rc = door_call(door_fd, &da);
154915894efSMatt Barden 
155915894efSMatt Barden 	if (rc < 0) {
156915894efSMatt Barden 		perror("door call #2 failed");
157915894efSMatt Barden 		exit(-9);
158915894efSMatt Barden 	}
159915894efSMatt Barden 
160915894efSMatt Barden 	(void) close(door_fd);
161915894efSMatt Barden 
162915894efSMatt Barden 	return (0);
163915894efSMatt Barden }
164