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 defined(__sparc) 99 /* 100 * This hasn't been implemented for SPARC, so skip. 101 */ 102 fprintf(stderr, "No SPARC implementation of get_stack_at_entry\n"); 103 return (3); 104 #else 105 if (pthread_create(&tid, NULL, 106 (void *(*)(void *))get_stack_at_entry, &arg) != 0) { 107 perror("pthread_create() failed:"); 108 exit(-2); 109 } 110 (void) pthread_join(tid, NULL); 111 112 arg.text = "thr_create()"; 113 114 if (thr_create(NULL, 0, (void *(*)(void *))get_stack_at_entry, 115 &arg, 0, &tid) != 0) { 116 perror("thr_create() failed:"); 117 exit(-3); 118 } 119 (void) thr_join(tid, NULL, NULL); 120 121 if (getcontext(&uc) < 0) { 122 perror("getcontext() failed"); 123 exit(-4); 124 } 125 126 uc.uc_link = &back; 127 uc.uc_stack.ss_size = STACK_SIZE; 128 uc.uc_stack.ss_flags = 0; 129 if ((uc.uc_stack.ss_sp = malloc(STACK_SIZE)) == NULL) { 130 perror("failed to allocate stack"); 131 exit(-5); 132 } 133 134 arg.text = "swapcontext()"; 135 makecontext(&uc, (void (*)(void *))get_stack_at_entry, 1, &arg); 136 if (swapcontext(&back, &uc) < 0) { 137 perror("swapcontext() failed"); 138 exit(-6); 139 } 140 141 arg.func = doorstack; 142 arg.text = "door_call()"; 143 144 if ((door_fd = door_create( 145 (door_server_procedure_t *)get_stack_at_entry, 146 &arg, 0)) < 0) { 147 perror("failed to create door"); 148 exit(-7); 149 } 150 151 rc = door_call(door_fd, &da); 152 153 if (rc < 0) { 154 perror("door call #1 failed"); 155 exit(-8); 156 } 157 158 da.data_size += 5; 159 rc = door_call(door_fd, &da); 160 161 if (rc < 0) { 162 perror("door call #2 failed"); 163 exit(-9); 164 } 165 166 (void) close(door_fd); 167 168 return (0); 169 #endif 170 } 171