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 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 63 initmain(uintptr_t stack) 64 { 65 teststack(stack, "section .init"); 66 } 67 68 void 69 initarray(uintptr_t stack) 70 { 71 teststack(stack, "section .init_array"); 72 } 73 74 void 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 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