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 2022 Oxide Computer Company 14 */ 15 16 /* 17 * This tool is used to try and figure out what the value of various static 18 * buffers should be and if the current compile time defaults are correct. In 19 * particular, this covers the various elfcap values and is used to drive how we 20 * calculate the overall size definition. 21 * 22 * To calculate this, we assume the following: 23 * 24 * o We are using the ELFCAP_FMT_PIPSPACE as that is the longest. We don't 25 * have access to the actual strings right now. 26 * o We are using the ELFCAP_STYLE_FULL variant of the name as that's the 27 * longest. 28 * o We are going to have leftover bits that we don't know (unless we have 29 * 32-bits defined). This uses the 0x%x format and therefore is 10 30 * characters. 31 * o We check all architectures set of values and take the largest. 32 * 33 * While elfcap related information is in multiple places in the build, sgs and 34 * libconv are the places that seem most intertwined. In particular, we believe 35 * it's important that this program execute as part of make check and also get 36 * rebuilt normally as part of a build. This also allows one to iterate in 37 * cmd/sgs which is the most common place that you're working in when adding new 38 * hardware capabilities. By making it a part of the cmd/sgs suite, that also 39 * ensures that normal build logic always rebuilds this program with changes to 40 * elfcap.[ch]. 41 */ 42 43 #include <stdio.h> 44 #include <elfcap.h> 45 #include <sys/sysmacros.h> 46 #include <stdlib.h> 47 48 /* 49 * The length of 0x%x. 50 */ 51 #define ECS_UNKNOWN 10 52 53 typedef const elfcap_desc_t *(*elfcap_getdesc_f)(void); 54 55 typedef struct elfcap_getdesc { 56 uint32_t eg_nents; 57 elfcap_getdesc_f eg_func; 58 } elfcap_getdesc_t; 59 60 #define NUM_PLATS 2 /* i386, sparc */ 61 62 typedef struct elfcap_case { 63 const char *ec_tag; 64 size_t ec_header; 65 elfcap_getdesc_t ec_descs[NUM_PLATS]; 66 } elfcap_case_t; 67 68 const elfcap_case_t elfcaps[] = { 69 { "ELFCAP_SF1_BUFSIZE", ELFCAP_SF1_BUFSIZE, { 70 { ELFCAP_NUM_SF1, elfcap_getdesc_sf1 }, 71 { 0, NULL } 72 } }, 73 { "ELFCAP_HW1_BUFSIZE", ELFCAP_HW1_BUFSIZE, { 74 { ELFCAP_NUM_HW1_386, elfcap_getdesc_hw1_386 }, 75 { ELFCAP_NUM_HW1_SPARC, elfcap_getdesc_hw1_sparc } 76 } }, 77 { "ELFCAP_HW2_BUFSIZE", ELFCAP_HW2_BUFSIZE, { 78 { ELFCAP_NUM_HW2_386, elfcap_getdesc_hw2_386 }, 79 { 0, NULL } 80 } }, 81 { "ELFCAP_HW3_BUFSIZE", ELFCAP_HW3_BUFSIZE, { 82 { ELFCAP_NUM_HW3_386, elfcap_getdesc_hw3_386 }, 83 { 0, NULL } 84 } }, 85 }; 86 87 static size_t 88 elfcap_calc_len(const elfcap_desc_t *desc, uint32_t nents, size_t space) 89 { 90 size_t len = 0; 91 92 for (uint32_t i = 0; i < nents; i++) { 93 len += desc[i].c_full.s_len; 94 if (i > 0) { 95 len += space; 96 } 97 } 98 99 if (nents < 32) { 100 len += space + ECS_UNKNOWN; 101 } 102 103 /* 104 * Finally, add one for a terminator and we add an 8 character buffer in 105 * case we screwed up. 106 */ 107 len += 9; 108 109 return (len); 110 } 111 112 static size_t 113 elfcap_max_len(const elfcap_case_t *ec, size_t slen) 114 { 115 size_t max = 0; 116 117 for (size_t i = 0; i < ARRAY_SIZE(ec->ec_descs); i++) { 118 const elfcap_desc_t *desc; 119 size_t len; 120 121 if (ec->ec_descs[i].eg_func == NULL) 122 continue; 123 124 desc = ec->ec_descs[i].eg_func(); 125 len = elfcap_calc_len(desc, ec->ec_descs[i].eg_nents, slen); 126 if (len > max) 127 max = len; 128 } 129 130 return (max); 131 } 132 133 int 134 main(void) 135 { 136 size_t slen; 137 const elfcap_str_t *strs; 138 int ret = EXIT_SUCCESS; 139 140 strs = elfcap_getdesc_formats(); 141 slen = strs[ELFCAP_FMT_PIPSPACE].s_len; 142 143 for (size_t i = 0; i < ARRAY_SIZE(elfcaps); i++) { 144 size_t out = elfcap_max_len(&elfcaps[i], slen); 145 146 if (out != elfcaps[i].ec_header) { 147 (void) fprintf(stderr, "elfcap size for %s is not " 148 "expected value!\n\tCurrent value is %zu, should " 149 "be %zu\n", elfcaps[i].ec_tag, elfcaps[i].ec_header, 150 out); 151 ret = EXIT_FAILURE; 152 } 153 } 154 155 if (ret != EXIT_SUCCESS) { 156 (void) fprintf(stderr, "please update $SRC/common/elfcap/" 157 "elfcap.h and $SRC/cmd/sgs/include/conv.h with the new " 158 "values reported above\n"); 159 } 160 161 return (ret); 162 } 163