xref: /illumos-gate/usr/src/tools/cpcgen/cpcgen.c (revision 43449cdc)
17e3dbbacSRobert Mustacchi /*
27e3dbbacSRobert Mustacchi  * This file and its contents are supplied under the terms of the
37e3dbbacSRobert Mustacchi  * Common Development and Distribution License ("CDDL"), version 1.0.
47e3dbbacSRobert Mustacchi  * You may only use this file in accordance with the terms of version
57e3dbbacSRobert Mustacchi  * 1.0 of the CDDL.
67e3dbbacSRobert Mustacchi  *
77e3dbbacSRobert Mustacchi  * A full copy of the text of the CDDL should have accompanied this
87e3dbbacSRobert Mustacchi  * source.  A copy of the CDDL is also available via the Internet at
97e3dbbacSRobert Mustacchi  * http://www.illumos.org/license/CDDL.
107e3dbbacSRobert Mustacchi  */
117e3dbbacSRobert Mustacchi 
127e3dbbacSRobert Mustacchi /*
1300fc50d1SJohn Levon  * Copyright 2019, Joyent, Inc.
14*43449cdcSRobert Mustacchi  * Copyright 2021 Oxide Computer Company
157e3dbbacSRobert Mustacchi  */
167e3dbbacSRobert Mustacchi 
177e3dbbacSRobert Mustacchi /*
18d0e58ef5SRobert Mustacchi  * This program transforms Intel perfmon and AMD PMC data files into C files and
19d0e58ef5SRobert Mustacchi  * manual pages.
207e3dbbacSRobert Mustacchi  */
217e3dbbacSRobert Mustacchi 
227e3dbbacSRobert Mustacchi #include <stdio.h>
237e3dbbacSRobert Mustacchi #include <stdarg.h>
247e3dbbacSRobert Mustacchi #include <unistd.h>
257e3dbbacSRobert Mustacchi #include <err.h>
267e3dbbacSRobert Mustacchi #include <libgen.h>
277e3dbbacSRobert Mustacchi #include <libnvpair.h>
287e3dbbacSRobert Mustacchi #include <strings.h>
297e3dbbacSRobert Mustacchi #include <errno.h>
307e3dbbacSRobert Mustacchi #include <limits.h>
317e3dbbacSRobert Mustacchi #include <sys/mman.h>
327e3dbbacSRobert Mustacchi #include <sys/param.h>
337e3dbbacSRobert Mustacchi #include <assert.h>
347e3dbbacSRobert Mustacchi #include <ctype.h>
357e3dbbacSRobert Mustacchi #include <sys/types.h>
367e3dbbacSRobert Mustacchi #include <sys/stat.h>
377e3dbbacSRobert Mustacchi #include <fcntl.h>
38d0e58ef5SRobert Mustacchi #include <dirent.h>
397e3dbbacSRobert Mustacchi 
407e3dbbacSRobert Mustacchi #include <json_nvlist.h>
417e3dbbacSRobert Mustacchi 
427e3dbbacSRobert Mustacchi #define	EXIT_USAGE	2
43c18e9bc3SRobert Mustacchi #define	CPROC_MAX_STEPPINGS	16
447e3dbbacSRobert Mustacchi 
45d0e58ef5SRobert Mustacchi typedef enum {
46d0e58ef5SRobert Mustacchi 	CPCGEN_MODE_UNKNOWN = 0,
47d0e58ef5SRobert Mustacchi 	CPCGEN_MODE_INTEL,
48d0e58ef5SRobert Mustacchi 	CPCGEN_MODE_AMD
49d0e58ef5SRobert Mustacchi } cpc_mode_t;
50d0e58ef5SRobert Mustacchi 
517e3dbbacSRobert Mustacchi typedef struct cpc_proc {
527e3dbbacSRobert Mustacchi 	struct cpc_proc *cproc_next;
537e3dbbacSRobert Mustacchi 	uint_t		cproc_family;
547e3dbbacSRobert Mustacchi 	uint_t		cproc_model;
55c18e9bc3SRobert Mustacchi 	uint_t		cproc_nsteps;
56c18e9bc3SRobert Mustacchi 	uint_t		cproc_steppings[CPROC_MAX_STEPPINGS];
577e3dbbacSRobert Mustacchi } cpc_proc_t;
587e3dbbacSRobert Mustacchi 
597e3dbbacSRobert Mustacchi typedef enum cpc_file_type {
607e3dbbacSRobert Mustacchi 	CPC_FILE_CORE		= 1 << 0,
617e3dbbacSRobert Mustacchi 	CPC_FILE_OFF_CORE	= 1 << 1,
627e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE		= 1 << 2,
637e3dbbacSRobert Mustacchi 	CPC_FILE_FP_MATH	= 1 << 3,
647e3dbbacSRobert Mustacchi 	CPC_FILE_UNCORE_EXP	= 1 << 4
657e3dbbacSRobert Mustacchi } cpc_type_t;
667e3dbbacSRobert Mustacchi 
677e3dbbacSRobert Mustacchi typedef struct cpc_map {
687e3dbbacSRobert Mustacchi 	struct cpc_map	*cmap_next;
697e3dbbacSRobert Mustacchi 	cpc_type_t	cmap_type;
707e3dbbacSRobert Mustacchi 	nvlist_t	*cmap_data;
717e3dbbacSRobert Mustacchi 	char		*cmap_path;
727e3dbbacSRobert Mustacchi 	const char	*cmap_name;
737e3dbbacSRobert Mustacchi 	cpc_proc_t	*cmap_procs;
747e3dbbacSRobert Mustacchi } cpc_map_t;
757e3dbbacSRobert Mustacchi 
767e3dbbacSRobert Mustacchi typedef struct cpc_whitelist {
777e3dbbacSRobert Mustacchi 	const char	*cwhite_short;
787e3dbbacSRobert Mustacchi 	const char	*cwhite_human;
797e3dbbacSRobert Mustacchi 	uint_t		cwhite_mask;
807e3dbbacSRobert Mustacchi } cpc_whitelist_t;
817e3dbbacSRobert Mustacchi 
827e3dbbacSRobert Mustacchi /*
837e3dbbacSRobert Mustacchi  * List of architectures that we support generating this data for. This is done
847e3dbbacSRobert Mustacchi  * so that processors that illumos doesn't support or run on aren't generated
857e3dbbacSRobert Mustacchi  * (generally the Xeon Phi).
867e3dbbacSRobert Mustacchi  */
87d0e58ef5SRobert Mustacchi static cpc_whitelist_t cpcgen_intel_whitelist[] = {
887e3dbbacSRobert Mustacchi 	/* Nehalem */
897e3dbbacSRobert Mustacchi 	{ "NHM-EP", "nhm_ep", CPC_FILE_CORE },
907e3dbbacSRobert Mustacchi 	{ "NHM-EX", "nhm_ex", CPC_FILE_CORE },
917e3dbbacSRobert Mustacchi 	/* Westmere */
927e3dbbacSRobert Mustacchi 	{ "WSM-EP-DP", "wsm_ep_dp", CPC_FILE_CORE },
937e3dbbacSRobert Mustacchi 	{ "WSM-EP-SP", "wsm_ep_sp", CPC_FILE_CORE },
947e3dbbacSRobert Mustacchi 	{ "WSM-EX", "wsm_ex", CPC_FILE_CORE },
957e3dbbacSRobert Mustacchi 	/* Sandy Bridge */
967e3dbbacSRobert Mustacchi 	{ "SNB", "snb", CPC_FILE_CORE },
977e3dbbacSRobert Mustacchi 	{ "JKT", "jkt", CPC_FILE_CORE },
987e3dbbacSRobert Mustacchi 	/* Ivy Bridge */
997e3dbbacSRobert Mustacchi 	{ "IVB", "ivb", CPC_FILE_CORE },
1007e3dbbacSRobert Mustacchi 	{ "IVT", "ivt", CPC_FILE_CORE },
1017e3dbbacSRobert Mustacchi 	/* Haswell */
1027e3dbbacSRobert Mustacchi 	{ "HSW", "hsw", CPC_FILE_CORE },
1037e3dbbacSRobert Mustacchi 	{ "HSX", "hsx", CPC_FILE_CORE },
1047e3dbbacSRobert Mustacchi 	/* Broadwell */
1057e3dbbacSRobert Mustacchi 	{ "BDW", "bdw", CPC_FILE_CORE },
1067e3dbbacSRobert Mustacchi 	{ "BDW-DE", "bdw_de", CPC_FILE_CORE },
1077e3dbbacSRobert Mustacchi 	{ "BDX", "bdx", CPC_FILE_CORE },
1087e3dbbacSRobert Mustacchi 	/* Skylake */
1097e3dbbacSRobert Mustacchi 	{ "SKL", "skl", CPC_FILE_CORE },
1107e3dbbacSRobert Mustacchi 	{ "SKX", "skx", CPC_FILE_CORE },
111c18e9bc3SRobert Mustacchi 	/* Cascade Lake */
112c18e9bc3SRobert Mustacchi 	{ "CLX", "clx", CPC_FILE_CORE },
113*43449cdcSRobert Mustacchi 	/* Ice Lake */
114*43449cdcSRobert Mustacchi 	{ "ICL", "icl", CPC_FILE_CORE },
115*43449cdcSRobert Mustacchi 	/* Tiger Lake */
116*43449cdcSRobert Mustacchi 	{ "TGL", "tgl", CPC_FILE_CORE },
1177e3dbbacSRobert Mustacchi 	/* Atom */
1187e3dbbacSRobert Mustacchi 	{ "BNL", "bnl", CPC_FILE_CORE },
1197e3dbbacSRobert Mustacchi 	{ "SLM", "slm", CPC_FILE_CORE },
1207e3dbbacSRobert Mustacchi 	{ "GLM", "glm", CPC_FILE_CORE },
1217e3dbbacSRobert Mustacchi 	{ "GLP", "glp", CPC_FILE_CORE },
122*43449cdcSRobert Mustacchi 	{ "SNR", "snr", CPC_FILE_CORE },
1237e3dbbacSRobert Mustacchi 	{ NULL }
1247e3dbbacSRobert Mustacchi };
1257e3dbbacSRobert Mustacchi 
1267e3dbbacSRobert Mustacchi typedef struct cpc_papi {
1277e3dbbacSRobert Mustacchi 	const char	*cpapi_intc;
1287e3dbbacSRobert Mustacchi 	const char	*cpapi_papi;
1297e3dbbacSRobert Mustacchi } cpc_papi_t;
1307e3dbbacSRobert Mustacchi 
1317e3dbbacSRobert Mustacchi /*
1327e3dbbacSRobert Mustacchi  * This table maps events with an Intel specific name to the corresponding PAPI
133c18e9bc3SRobert Mustacchi  * name. There may be multiple Intel events which map to the same PAPI event.
1347e3dbbacSRobert Mustacchi  * This is usually because different processors have different names for an
1357e3dbbacSRobert Mustacchi  * event. We use the title as opposed to the event codes because those can
1367e3dbbacSRobert Mustacchi  * change somewhat arbitrarily between processor generations.
1377e3dbbacSRobert Mustacchi  */
138d0e58ef5SRobert Mustacchi static cpc_papi_t cpcgen_intel_papi_map[] = {
1397e3dbbacSRobert Mustacchi 	{ "CPU_CLK_UNHALTED.THREAD_P", "PAPI_tot_cyc" },
1407e3dbbacSRobert Mustacchi 	{ "INST_RETIRED.ANY_P", "PAPI_tot_ins" },
1417e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.ALL_BRANCHES", "PAPI_br_ins" },
1427e3dbbacSRobert Mustacchi 	{ "BR_MISP_RETIRED.ALL_BRANCHES", "PAPI_br_msp" },
1437e3dbbacSRobert Mustacchi 	{ "BR_INST_RETIRED.CONDITIONAL", "PAPI_br_cn" },
1447e3dbbacSRobert Mustacchi 	{ "CYCLE_ACTIVITY.CYCLES_L1D_MISS", "PAPI_l1_dcm" },
1457e3dbbacSRobert Mustacchi 	{ "L1I.HITS", "PAPI_l1_ich" },
1467e3dbbacSRobert Mustacchi 	{ "ICACHE.HIT", "PAPI_l1_ich" },
1477e3dbbacSRobert Mustacchi 	{ "L1I.MISS", "PAPI_L1_icm" },
1487e3dbbacSRobert Mustacchi 	{ "ICACHE.MISSES", "PAPI_l1_icm" },
1497e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_ica" },
1507e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_ica" },
1517e3dbbacSRobert Mustacchi 	{ "L1I.READS", "PAPI_l1_icr" },
1527e3dbbacSRobert Mustacchi 	{ "ICACHE.ACCESSES", "PAPI_l1_icr" },
1537e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.CODE_RD_MISS", "PAPI_l2_icm" },
1547e3dbbacSRobert Mustacchi 	{ "L2_RQSTS.MISS", "PAPI_l2_tcm" },
1557e3dbbacSRobert Mustacchi 	{ "ITLB_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_im" },
1567e3dbbacSRobert Mustacchi 	{ "DTLB_LOAD_MISSES.MISS_CAUSES_A_WALK", "PAPI_tlb_dm" },
1577e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.D_SIDE_WALKS", "PAPI_tlb_dm" },
1587e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.I_SIDE_WALKS", "PAPI_tlb_im" },
1597e3dbbacSRobert Mustacchi 	{ "PAGE_WALKS.WALKS", "PAPI_tlb_tl" },
1607e3dbbacSRobert Mustacchi 	{ "INST_QUEUE_WRITES", "PAPI_tot_iis" },
1617e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.STORES" "PAPI_sr_ins" },
1627e3dbbacSRobert Mustacchi 	{ "MEM_INST_RETIRED.LOADS" "PAPI_ld_ins" },
1637e3dbbacSRobert Mustacchi 	{ NULL, NULL }
1647e3dbbacSRobert Mustacchi };
1657e3dbbacSRobert Mustacchi 
1667e3dbbacSRobert Mustacchi typedef struct cpcgen_ops {
167d0e58ef5SRobert Mustacchi 	void (*cgen_op_gather)(const char *, const char *);
168d0e58ef5SRobert Mustacchi 	void (*cgen_op_common)(int);
1697e3dbbacSRobert Mustacchi 	char *(*cgen_op_name)(cpc_map_t *);
170d0e58ef5SRobert Mustacchi 	boolean_t (*cgen_op_skip)(nvlist_t *, const char *, uint_t);
1717e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_before)(FILE *, cpc_map_t *);
1727e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_file_after)(FILE *, cpc_map_t *);
1737e3dbbacSRobert Mustacchi 	boolean_t (*cgen_op_event)(FILE *, nvlist_t *, const char *, uint32_t);
1747e3dbbacSRobert Mustacchi } cpcgen_ops_t;
1757e3dbbacSRobert Mustacchi 
1767e3dbbacSRobert Mustacchi static cpcgen_ops_t cpcgen_ops;
177d0e58ef5SRobert Mustacchi static const char *cpcgen_intel_mapfile = "/mapfile.csv";
1787e3dbbacSRobert Mustacchi static const char *cpcgen_progname;
1797e3dbbacSRobert Mustacchi static cpc_map_t *cpcgen_maps;
180d0e58ef5SRobert Mustacchi static cpc_mode_t cpcgen_mode = CPCGEN_MODE_UNKNOWN;
1817e3dbbacSRobert Mustacchi 
1827e3dbbacSRobert Mustacchi /*
1837e3dbbacSRobert Mustacchi  * Constants used for generating data.
1847e3dbbacSRobert Mustacchi  */
1857e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
186d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_intel_header = ""
1877e3dbbacSRobert Mustacchi "/*\n"
1887e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Intel Corporation\n"
1897e3dbbacSRobert Mustacchi " *  Copyright (c) 2018, Joyent, Inc\n"
1907e3dbbacSRobert Mustacchi " *  All rights reserved.\n"
1917e3dbbacSRobert Mustacchi " *\n"
1927e3dbbacSRobert Mustacchi " *  Redistribution and use in source and binary forms, with or without\n"
1937e3dbbacSRobert Mustacchi " *  modification, are permitted provided that the following conditions are met:\n"
1947e3dbbacSRobert Mustacchi " * \n"
1957e3dbbacSRobert Mustacchi " *   1. Redistributions of source code must retain the above copyright notice,\n"
1967e3dbbacSRobert Mustacchi " *      this list of conditions and the following disclaimer.\n"
1977e3dbbacSRobert Mustacchi " * \n"
1987e3dbbacSRobert Mustacchi " *   2. Redistributions in binary form must reproduce the above copyright \n"
1997e3dbbacSRobert Mustacchi " *      notice, this list of conditions and the following disclaimer in the\n"
2007e3dbbacSRobert Mustacchi " *      documentation and/or other materials provided with the distribution.\n"
2017e3dbbacSRobert Mustacchi " * \n"
2027e3dbbacSRobert Mustacchi " *   3. Neither the name of the Intel Corporation nor the names of its \n"
2037e3dbbacSRobert Mustacchi " *      contributors may be used to endorse or promote products derived from\n"
2047e3dbbacSRobert Mustacchi " *      this software without specific prior written permission.\n"
2057e3dbbacSRobert Mustacchi " *\n"
2067e3dbbacSRobert Mustacchi " *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
2077e3dbbacSRobert Mustacchi " *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
2087e3dbbacSRobert Mustacchi " *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
2097e3dbbacSRobert Mustacchi " *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
2107e3dbbacSRobert Mustacchi " *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
2117e3dbbacSRobert Mustacchi " *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
2127e3dbbacSRobert Mustacchi " *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
2137e3dbbacSRobert Mustacchi " *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
2147e3dbbacSRobert Mustacchi " *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
2157e3dbbacSRobert Mustacchi " *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
2167e3dbbacSRobert Mustacchi " *  POSSIBILITY OF SUCH DAMAGE.\n"
2177e3dbbacSRobert Mustacchi " *\n"
2187e3dbbacSRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
2197e3dbbacSRobert Mustacchi " * data/perfmon%s\n"
2207e3dbbacSRobert Mustacchi " *\n"
2217e3dbbacSRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
2227e3dbbacSRobert Mustacchi " */\n"
2237e3dbbacSRobert Mustacchi "\n";
2247e3dbbacSRobert Mustacchi /* END CSTYLED */
2257e3dbbacSRobert Mustacchi 
226d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_intel_table_start = ""
2277e3dbbacSRobert Mustacchi "#include <core_pcbe_table.h>\n"
2287e3dbbacSRobert Mustacchi "\n"
2297e3dbbacSRobert Mustacchi "const struct events_table_t pcbe_core_events_%s[] = {\n";
2307e3dbbacSRobert Mustacchi 
231d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_intel_table_end = ""
2327e3dbbacSRobert Mustacchi "\t{ NT_END, 0, 0, \"\" }\n"
2337e3dbbacSRobert Mustacchi "};\n";
2347e3dbbacSRobert Mustacchi 
2357e3dbbacSRobert Mustacchi /* BEGIN CSTYLED */
236d0e58ef5SRobert Mustacchi static const char *cpcgen_manual_intel_intel_header = ""
2377e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Intel Corporation \n"
2387e3dbbacSRobert Mustacchi ".\\\" Copyright (c) 2018, Joyent, Inc.\n"
2397e3dbbacSRobert Mustacchi ".\\\" All rights reserved.\n"
2407e3dbbacSRobert Mustacchi ".\\\"\n"
2417e3dbbacSRobert Mustacchi ".\\\" Redistribution and use in source and binary forms, with or without \n"
2427e3dbbacSRobert Mustacchi ".\\\" modification, are permitted provided that the following conditions are met:\n"
2437e3dbbacSRobert Mustacchi ".\\\"\n"
2447e3dbbacSRobert Mustacchi ".\\\"  1. Redistributions of source code must retain the above copyright notice,\n"
2457e3dbbacSRobert Mustacchi ".\\\"     this list of conditions and the following disclaimer.\n"
2467e3dbbacSRobert Mustacchi ".\\\"\n"
2477e3dbbacSRobert Mustacchi ".\\\"  2. Redistributions in binary form must reproduce the above copyright\n"
2487e3dbbacSRobert Mustacchi ".\\\"     notice, this list of conditions and the following disclaimer in the\n"
2497e3dbbacSRobert Mustacchi ".\\\"     documentation and/or other materials provided with the distribution.\n"
2507e3dbbacSRobert Mustacchi ".\\\"\n"
2517e3dbbacSRobert Mustacchi ".\\\"  3. Neither the name of the Intel Corporation nor the names of its\n"
2527e3dbbacSRobert Mustacchi ".\\\"     contributors may be used to endorse or promote products derived from\n"
2537e3dbbacSRobert Mustacchi ".\\\"     this software without specific prior written permission.\n"
2547e3dbbacSRobert Mustacchi ".\\\"\n"
2557e3dbbacSRobert Mustacchi ".\\\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n"
2567e3dbbacSRobert Mustacchi ".\\\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
2577e3dbbacSRobert Mustacchi ".\\\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
2587e3dbbacSRobert Mustacchi ".\\\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n"
2597e3dbbacSRobert Mustacchi ".\\\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n"
2607e3dbbacSRobert Mustacchi ".\\\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n"
2617e3dbbacSRobert Mustacchi ".\\\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
2627e3dbbacSRobert Mustacchi ".\\\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n"
2637e3dbbacSRobert Mustacchi ".\\\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n"
2647e3dbbacSRobert Mustacchi ".\\\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n"
2657e3dbbacSRobert Mustacchi ".\\\" POSSIBILITY OF SUCH DAMAGE.\n"
2667e3dbbacSRobert Mustacchi ".\\\"\n"
2677e3dbbacSRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
2687e3dbbacSRobert Mustacchi ".\\\" data/perfmon%s\n"
2697e3dbbacSRobert Mustacchi ".\\\"\n"
2707e3dbbacSRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
2717e3dbbacSRobert Mustacchi ".\\\"\n"
2727e3dbbacSRobert Mustacchi ".\\\" We would like to thank Intel for providing the perfmon data for use in\n"
2737e3dbbacSRobert Mustacchi ".\\\" our manual pages.\n"
2747e3dbbacSRobert Mustacchi ".Dd June 18, 2018\n"
2757e3dbbacSRobert Mustacchi ".Dt %s_EVENTS 3CPC\n"
2767e3dbbacSRobert Mustacchi ".Os\n"
2777e3dbbacSRobert Mustacchi ".Sh NAME\n"
2787e3dbbacSRobert Mustacchi ".Nm %s_events\n"
2797e3dbbacSRobert Mustacchi ".Nd processor model specific performance counter events\n"
2807e3dbbacSRobert Mustacchi ".Sh DESCRIPTION\n"
2817e3dbbacSRobert Mustacchi "This manual page describes events specific to the following Intel CPU\n"
2827e3dbbacSRobert Mustacchi "models and is derived from Intel's perfmon data.\n"
2837e3dbbacSRobert Mustacchi "For more information, please consult the Intel Software Developer's Manual "
2847e3dbbacSRobert Mustacchi "or Intel's perfmon website.\n"
2857e3dbbacSRobert Mustacchi ".Pp\n"
2867e3dbbacSRobert Mustacchi "CPU models described by this document:\n"
2877e3dbbacSRobert Mustacchi ".Bl -bullet\n";
2887e3dbbacSRobert Mustacchi /* END CSTYLED */
2897e3dbbacSRobert Mustacchi 
290d0e58ef5SRobert Mustacchi static const char *cpcgen_manual_intel_data = ""
2917e3dbbacSRobert Mustacchi ".El\n"
2927e3dbbacSRobert Mustacchi ".Pp\n"
2937e3dbbacSRobert Mustacchi "The following events are supported:\n"
2947e3dbbacSRobert Mustacchi ".Bl -tag -width Sy\n";
2957e3dbbacSRobert Mustacchi 
296d0e58ef5SRobert Mustacchi static const char *cpcgen_manual_intel_trailer = ""
2977e3dbbacSRobert Mustacchi ".El\n"
2987e3dbbacSRobert Mustacchi ".Sh SEE ALSO\n"
2997e3dbbacSRobert Mustacchi ".Xr cpc 3CPC\n"
3007e3dbbacSRobert Mustacchi ".Pp\n"
3017e3dbbacSRobert Mustacchi ".Lk https://download.01.org/perfmon/index/";
3027e3dbbacSRobert Mustacchi 
303d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_cddl_header = ""
304d0e58ef5SRobert Mustacchi "/*\n"
305d0e58ef5SRobert Mustacchi " * This file and its contents are supplied under the terms of the\n"
306d0e58ef5SRobert Mustacchi " * Common Development and Distribution License (\"CDDL\"), version 1.0.\n"
307d0e58ef5SRobert Mustacchi " * You may only use this file in accordance with the terms of version\n"
308d0e58ef5SRobert Mustacchi " * 1.0 of the CDDL.\n"
309d0e58ef5SRobert Mustacchi " *\n"
310d0e58ef5SRobert Mustacchi " * A full copy of the text of the CDDL should have accompanied this\n"
311d0e58ef5SRobert Mustacchi " * source.  A copy of the CDDL is also available via the Internet at\n"
312d0e58ef5SRobert Mustacchi " * http://www.illumos.org/license/CDDL.\n"
313d0e58ef5SRobert Mustacchi " */\n"
314d0e58ef5SRobert Mustacchi "\n"
315d0e58ef5SRobert Mustacchi "/*\n"
316d0e58ef5SRobert Mustacchi " * Copyright 2019 Joyent, Inc\n"
317d0e58ef5SRobert Mustacchi " */\n"
318d0e58ef5SRobert Mustacchi "\n"
319d0e58ef5SRobert Mustacchi "/*\n"
320d0e58ef5SRobert Mustacchi " * This file was automatically generated by cpcgen.\n"
321d0e58ef5SRobert Mustacchi " */\n"
322d0e58ef5SRobert Mustacchi "\n"
323d0e58ef5SRobert Mustacchi "/*\n"
324d0e58ef5SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
325d0e58ef5SRobert Mustacchi " */\n"
326d0e58ef5SRobert Mustacchi "\n";
327d0e58ef5SRobert Mustacchi 
328d0e58ef5SRobert Mustacchi static const char *cpcgen_manual_amd_header = ""
329d0e58ef5SRobert Mustacchi ".\\\" This file was automatically generated by cpcgen from the data file\n"
330d0e58ef5SRobert Mustacchi ".\\\" data/amdpmc/%s\n"
331d0e58ef5SRobert Mustacchi ".\\\"\n"
332d0e58ef5SRobert Mustacchi ".\\\" Do not modify this file. Your changes will be lost!\n"
333d0e58ef5SRobert Mustacchi ".\\\"\n"
334d0e58ef5SRobert Mustacchi ".\\\" We would like to thank AMD for providing the PMC data for use in\n"
335d0e58ef5SRobert Mustacchi ".\\\" our manual pages.\n"
336d0e58ef5SRobert Mustacchi ".Dd March 25, 2019\n"
337d0e58ef5SRobert Mustacchi ".Dt AMD_%s_EVENTS 3CPC\n"
338d0e58ef5SRobert Mustacchi ".Os\n"
339d0e58ef5SRobert Mustacchi ".Sh NAME\n"
340d0e58ef5SRobert Mustacchi ".Nm amd_%s_events\n"
34131aa6202SRobert Mustacchi ".Nd AMD Family %s processor performance monitoring events\n"
342d0e58ef5SRobert Mustacchi ".Sh DESCRIPTION\n"
34331aa6202SRobert Mustacchi "This manual page describes events specfic to AMD Family %s processors.\n"
344d0e58ef5SRobert Mustacchi "For more information, please consult the appropriate AMD BIOS and Kernel\n"
34531aa6202SRobert Mustacchi "Developer's guide or Open-Source Register Reference.\n"
346d0e58ef5SRobert Mustacchi ".Pp\n"
347d0e58ef5SRobert Mustacchi "Each of the events listed below includes the AMD mnemonic which matches\n"
348d0e58ef5SRobert Mustacchi "the name found in the AMD manual and a brief summary of the event.\n"
349d0e58ef5SRobert Mustacchi "If available, a more detailed description of the event follows and then\n"
350d0e58ef5SRobert Mustacchi "any additional unit values that modify the event.\n"
351d0e58ef5SRobert Mustacchi "Each unit can be combined to create a new event in the system by placing\n"
352d0e58ef5SRobert Mustacchi "the '.' character between the event name and the unit name.\n"
353d0e58ef5SRobert Mustacchi ".Pp\n"
354d0e58ef5SRobert Mustacchi "The following events are supported:\n"
355d0e58ef5SRobert Mustacchi ".Bl -tag -width Sy\n";
356d0e58ef5SRobert Mustacchi 
357d0e58ef5SRobert Mustacchi static const char *cpcgen_manual_amd_trailer = ""
358d0e58ef5SRobert Mustacchi ".El\n"
359d0e58ef5SRobert Mustacchi ".Sh SEE ALSO\n"
360d0e58ef5SRobert Mustacchi ".Xr cpc 3CPC\n";
361d0e58ef5SRobert Mustacchi 
362d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_amd_header = ""
363d0e58ef5SRobert Mustacchi "/*\n"
364d0e58ef5SRobert Mustacchi " * This file was automatically generated by cpcgen from the data file\n"
365d0e58ef5SRobert Mustacchi " * data/perfmon%s\n"
366d0e58ef5SRobert Mustacchi " *\n"
367d0e58ef5SRobert Mustacchi " * Do not modify this file. Your changes will be lost!\n"
368d0e58ef5SRobert Mustacchi " */\n"
369d0e58ef5SRobert Mustacchi "\n";
370d0e58ef5SRobert Mustacchi 
371d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_amd_table_start = ""
372d0e58ef5SRobert Mustacchi "#include <opteron_pcbe_table.h>\n"
373d0e58ef5SRobert Mustacchi "#include <sys/null.h>\n"
374d0e58ef5SRobert Mustacchi "\n"
375d0e58ef5SRobert Mustacchi "const amd_event_t opteron_pcbe_%s_events[] = {\n";
376d0e58ef5SRobert Mustacchi 
377d0e58ef5SRobert Mustacchi static const char *cpcgen_cfile_amd_table_end = ""
378d0e58ef5SRobert Mustacchi "\t{ NULL, 0, 0 }\n"
379d0e58ef5SRobert Mustacchi "};\n";
380d0e58ef5SRobert Mustacchi 
3817e3dbbacSRobert Mustacchi static cpc_map_t *
3827e3dbbacSRobert Mustacchi cpcgen_map_lookup(const char *path)
3837e3dbbacSRobert Mustacchi {
3847e3dbbacSRobert Mustacchi 	cpc_map_t *m;
3857e3dbbacSRobert Mustacchi 
3867e3dbbacSRobert Mustacchi 	for (m = cpcgen_maps; m != NULL; m = m->cmap_next) {
3877e3dbbacSRobert Mustacchi 		if (strcmp(path, m->cmap_path) == 0) {
3887e3dbbacSRobert Mustacchi 			return (m);
3897e3dbbacSRobert Mustacchi 		}
3907e3dbbacSRobert Mustacchi 	}
3917e3dbbacSRobert Mustacchi 
3927e3dbbacSRobert Mustacchi 	return (NULL);
3937e3dbbacSRobert Mustacchi }
3947e3dbbacSRobert Mustacchi 
3957e3dbbacSRobert Mustacchi /*
3967e3dbbacSRobert Mustacchi  * Parse a string of the form 'GenuineIntel-6-2E' and get out the family and
3977e3dbbacSRobert Mustacchi  * model.
3987e3dbbacSRobert Mustacchi  */
3997e3dbbacSRobert Mustacchi static void
400c18e9bc3SRobert Mustacchi cpcgen_parse_model(char *fsr, uint_t *family, uint_t *model, uint_t *nstepp,
401c18e9bc3SRobert Mustacchi     uint_t *steppings)
4027e3dbbacSRobert Mustacchi {
4037e3dbbacSRobert Mustacchi 	const char *bstr = "GenuineIntel";
404c18e9bc3SRobert Mustacchi 	const char *brand, *fam, *mod, *step;
4057e3dbbacSRobert Mustacchi 	char *last;
4067e3dbbacSRobert Mustacchi 	long l;
407c18e9bc3SRobert Mustacchi 	uint_t nstep = 0;
4087e3dbbacSRobert Mustacchi 
409c18e9bc3SRobert Mustacchi 	/*
410c18e9bc3SRobert Mustacchi 	 * Tokeninze the string. There may be an optional stepping portion,
411c18e9bc3SRobert Mustacchi 	 * which has a range of steppings enclosed by '[' and ']' characters.
412c18e9bc3SRobert Mustacchi 	 * While the other parts are required, the stepping may be missing.
413c18e9bc3SRobert Mustacchi 	 */
4147e3dbbacSRobert Mustacchi 	if ((brand = strtok_r(fsr, "-", &last)) == NULL ||
4157e3dbbacSRobert Mustacchi 	    (fam = strtok_r(NULL, "-", &last)) == NULL ||
4167e3dbbacSRobert Mustacchi 	    (mod = strtok_r(NULL, "-", &last)) == NULL) {
4177e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse processor id \"%s\"", fsr);
4187e3dbbacSRobert Mustacchi 	}
419c18e9bc3SRobert Mustacchi 	step = strtok_r(NULL, "-", &last);
4207e3dbbacSRobert Mustacchi 
4217e3dbbacSRobert Mustacchi 	if (strcmp(bstr, brand) != 0) {
4227e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "brand string \"%s\" did not match \"%s\"",
4237e3dbbacSRobert Mustacchi 		    brand, bstr);
4247e3dbbacSRobert Mustacchi 	}
4257e3dbbacSRobert Mustacchi 
4267e3dbbacSRobert Mustacchi 	errno = 0;
4277e3dbbacSRobert Mustacchi 	l = strtol(fam, &last, 16);
42800fc50d1SJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
4297e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse family \"%s\"", fam);
4307e3dbbacSRobert Mustacchi 	}
4317e3dbbacSRobert Mustacchi 	*family = (uint_t)l;
4327e3dbbacSRobert Mustacchi 
4337e3dbbacSRobert Mustacchi 	l = strtol(mod, &last, 16);
43400fc50d1SJohn Levon 	if (errno != 0 || l < 0 || l >= INT_MAX || *last != '\0') {
4357e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse model \"%s\"", mod);
4367e3dbbacSRobert Mustacchi 	}
4377e3dbbacSRobert Mustacchi 	*model = (uint_t)l;
438c18e9bc3SRobert Mustacchi 
439c18e9bc3SRobert Mustacchi 	if (step == NULL) {
440c18e9bc3SRobert Mustacchi 		*nstepp = 0;
441c18e9bc3SRobert Mustacchi 		return;
442c18e9bc3SRobert Mustacchi 	}
443c18e9bc3SRobert Mustacchi 
444c18e9bc3SRobert Mustacchi 	if (*step != '[' || ((last = strrchr(step, ']')) == NULL)) {
445c18e9bc3SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse stepping \"%s\": missing "
446c18e9bc3SRobert Mustacchi 		    "stepping range brackets", step);
447c18e9bc3SRobert Mustacchi 	}
448c18e9bc3SRobert Mustacchi 	step++;
449c18e9bc3SRobert Mustacchi 	*last = '\0';
450c18e9bc3SRobert Mustacchi 	while (*step != '\0') {
451c18e9bc3SRobert Mustacchi 		if (!isxdigit(*step)) {
452c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: invalid "
453c18e9bc3SRobert Mustacchi 			    "stepping identifier '0x%x'", *step);
454c18e9bc3SRobert Mustacchi 		}
455c18e9bc3SRobert Mustacchi 
456c18e9bc3SRobert Mustacchi 		if (nstep >= CPROC_MAX_STEPPINGS) {
457c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse stepping: "
458c18e9bc3SRobert Mustacchi 			    "encountered too many steppings");
459c18e9bc3SRobert Mustacchi 		}
460c18e9bc3SRobert Mustacchi 
461c18e9bc3SRobert Mustacchi 		switch (*step) {
462c18e9bc3SRobert Mustacchi 		case '0':
463c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x0;
464c18e9bc3SRobert Mustacchi 			break;
465c18e9bc3SRobert Mustacchi 		case '1':
466c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x1;
467c18e9bc3SRobert Mustacchi 			break;
468c18e9bc3SRobert Mustacchi 		case '2':
469c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x2;
470c18e9bc3SRobert Mustacchi 			break;
471c18e9bc3SRobert Mustacchi 		case '3':
472c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x3;
473c18e9bc3SRobert Mustacchi 			break;
474c18e9bc3SRobert Mustacchi 		case '4':
475c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x4;
476c18e9bc3SRobert Mustacchi 			break;
477c18e9bc3SRobert Mustacchi 		case '5':
478c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x5;
479c18e9bc3SRobert Mustacchi 			break;
480c18e9bc3SRobert Mustacchi 		case '6':
481c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x6;
482c18e9bc3SRobert Mustacchi 			break;
483c18e9bc3SRobert Mustacchi 		case '7':
484c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x7;
485c18e9bc3SRobert Mustacchi 			break;
486c18e9bc3SRobert Mustacchi 		case '8':
487c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x8;
488c18e9bc3SRobert Mustacchi 			break;
489c18e9bc3SRobert Mustacchi 		case '9':
490c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0x9;
491c18e9bc3SRobert Mustacchi 			break;
492c18e9bc3SRobert Mustacchi 		case 'a':
493c18e9bc3SRobert Mustacchi 		case 'A':
494c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xa;
495c18e9bc3SRobert Mustacchi 			break;
496c18e9bc3SRobert Mustacchi 		case 'b':
497c18e9bc3SRobert Mustacchi 		case 'B':
498c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xb;
499c18e9bc3SRobert Mustacchi 			break;
500c18e9bc3SRobert Mustacchi 		case 'c':
501c18e9bc3SRobert Mustacchi 		case 'C':
502c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xc;
503c18e9bc3SRobert Mustacchi 			break;
504c18e9bc3SRobert Mustacchi 		case 'd':
505c18e9bc3SRobert Mustacchi 		case 'D':
506c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xd;
507c18e9bc3SRobert Mustacchi 			break;
508c18e9bc3SRobert Mustacchi 		case 'e':
509c18e9bc3SRobert Mustacchi 		case 'E':
510c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xe;
511c18e9bc3SRobert Mustacchi 			break;
512c18e9bc3SRobert Mustacchi 		case 'f':
513c18e9bc3SRobert Mustacchi 		case 'F':
514c18e9bc3SRobert Mustacchi 			steppings[nstep] = 0xf;
515c18e9bc3SRobert Mustacchi 			break;
516c18e9bc3SRobert Mustacchi 		default:
517c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "encountered non-hex stepping "
518c18e9bc3SRobert Mustacchi 			    "character: '%c'", *step);
519c18e9bc3SRobert Mustacchi 		}
520c18e9bc3SRobert Mustacchi 		nstep++;
521c18e9bc3SRobert Mustacchi 		step++;
522c18e9bc3SRobert Mustacchi 	}
523c18e9bc3SRobert Mustacchi 
524c18e9bc3SRobert Mustacchi 	*nstepp = nstep;
5257e3dbbacSRobert Mustacchi }
5267e3dbbacSRobert Mustacchi 
5277e3dbbacSRobert Mustacchi static nvlist_t *
5287e3dbbacSRobert Mustacchi cpcgen_read_datafile(const char *datadir, const char *file)
5297e3dbbacSRobert Mustacchi {
5307e3dbbacSRobert Mustacchi 	int fd;
5317e3dbbacSRobert Mustacchi 	char *path;
5327e3dbbacSRobert Mustacchi 	struct stat st;
5337e3dbbacSRobert Mustacchi 	void *map;
5347e3dbbacSRobert Mustacchi 	nvlist_t *nvl;
5357e3dbbacSRobert Mustacchi 	nvlist_parse_json_error_t jerr;
5367e3dbbacSRobert Mustacchi 
5377e3dbbacSRobert Mustacchi 	if (asprintf(&path, "%s/%s", datadir, file) == -1) {
5387e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to data file %s",
5397e3dbbacSRobert Mustacchi 		    file);
5407e3dbbacSRobert Mustacchi 	}
5417e3dbbacSRobert Mustacchi 
5427e3dbbacSRobert Mustacchi 	if ((fd = open(path, O_RDONLY)) < 0) {
5437e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data file %s", path);
5447e3dbbacSRobert Mustacchi 	}
5457e3dbbacSRobert Mustacchi 
5467e3dbbacSRobert Mustacchi 	if (fstat(fd, &st) != 0) {
5477e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to stat %s", path);
5487e3dbbacSRobert Mustacchi 	}
5497e3dbbacSRobert Mustacchi 
5507e3dbbacSRobert Mustacchi 	if ((map = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE,
5517e3dbbacSRobert Mustacchi 	    fd, 0)) == MAP_FAILED) {
5527e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to mmap %s", path);
5537e3dbbacSRobert Mustacchi 	}
5547e3dbbacSRobert Mustacchi 
5557e3dbbacSRobert Mustacchi 	if (nvlist_parse_json(map, st.st_size, &nvl, NVJSON_FORCE_INTEGER,
5567e3dbbacSRobert Mustacchi 	    &jerr) != 0) {
5577e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to parse file %s at pos %ld: %s",
5587e3dbbacSRobert Mustacchi 		    path, jerr.nje_pos, jerr.nje_message);
5597e3dbbacSRobert Mustacchi 	}
5607e3dbbacSRobert Mustacchi 
5617e3dbbacSRobert Mustacchi 	if (munmap(map, st.st_size) != 0) {
5627e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to munmap %s", path);
5637e3dbbacSRobert Mustacchi 	}
5647e3dbbacSRobert Mustacchi 
5657e3dbbacSRobert Mustacchi 	if (close(fd) != 0) {
5667e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close data file %s", path);
5677e3dbbacSRobert Mustacchi 	}
5687e3dbbacSRobert Mustacchi 	free(path);
5697e3dbbacSRobert Mustacchi 
5707e3dbbacSRobert Mustacchi 	return (nvl);
5717e3dbbacSRobert Mustacchi }
5727e3dbbacSRobert Mustacchi 
5737e3dbbacSRobert Mustacchi /*
5747e3dbbacSRobert Mustacchi  * Check the whitelist to see if we should use this model.
5757e3dbbacSRobert Mustacchi  */
5767e3dbbacSRobert Mustacchi static const char *
5777e3dbbacSRobert Mustacchi cpcgen_use_arch(const char *path, cpc_type_t type, const char *platform)
5787e3dbbacSRobert Mustacchi {
5797e3dbbacSRobert Mustacchi 	const char *slash;
5807e3dbbacSRobert Mustacchi 	size_t len;
5817e3dbbacSRobert Mustacchi 	uint_t i;
5827e3dbbacSRobert Mustacchi 
5837e3dbbacSRobert Mustacchi 	if (*path != '/') {
5847e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
5857e3dbbacSRobert Mustacchi 		    "leading '/'", path);
5867e3dbbacSRobert Mustacchi 	}
5877e3dbbacSRobert Mustacchi 	if ((slash = strchr(path + 1, '/')) == NULL) {
5887e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "invalid path in mapfile: \"%s\": missing "
5897e3dbbacSRobert Mustacchi 		    "second '/'", path);
5907e3dbbacSRobert Mustacchi 	}
5917e3dbbacSRobert Mustacchi 	/* Account for the last '/' character. */
5927e3dbbacSRobert Mustacchi 	len = slash - path - 1;
5937e3dbbacSRobert Mustacchi 	assert(len > 0);
5947e3dbbacSRobert Mustacchi 
595d0e58ef5SRobert Mustacchi 	for (i = 0; cpcgen_intel_whitelist[i].cwhite_short != NULL; i++) {
5967e3dbbacSRobert Mustacchi 		if (platform != NULL && strcasecmp(platform,
597d0e58ef5SRobert Mustacchi 		    cpcgen_intel_whitelist[i].cwhite_short) != 0)
5987e3dbbacSRobert Mustacchi 			continue;
599d0e58ef5SRobert Mustacchi 		if (strncmp(path + 1, cpcgen_intel_whitelist[i].cwhite_short,
6007e3dbbacSRobert Mustacchi 		    len) == 0 &&
601d0e58ef5SRobert Mustacchi 		    (cpcgen_intel_whitelist[i].cwhite_mask & type) == type) {
602d0e58ef5SRobert Mustacchi 			return (cpcgen_intel_whitelist[i].cwhite_human);
6037e3dbbacSRobert Mustacchi 		}
6047e3dbbacSRobert Mustacchi 	}
6057e3dbbacSRobert Mustacchi 
6067e3dbbacSRobert Mustacchi 	return (NULL);
6077e3dbbacSRobert Mustacchi }
6087e3dbbacSRobert Mustacchi 
609d0e58ef5SRobert Mustacchi /*
610d0e58ef5SRobert Mustacchi  * Determine which CPU Vendor we're transmuting data from.
611d0e58ef5SRobert Mustacchi  */
612d0e58ef5SRobert Mustacchi static void
613d0e58ef5SRobert Mustacchi cpcgen_determine_vendor(const char *datadir)
614d0e58ef5SRobert Mustacchi {
615d0e58ef5SRobert Mustacchi 	char *mappath;
616d0e58ef5SRobert Mustacchi 	struct stat st;
617d0e58ef5SRobert Mustacchi 
618d0e58ef5SRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_intel_mapfile) == -1) {
619d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
620d0e58ef5SRobert Mustacchi 	}
621d0e58ef5SRobert Mustacchi 
622d0e58ef5SRobert Mustacchi 	if (stat(mappath, &st) == 0) {
623d0e58ef5SRobert Mustacchi 		cpcgen_mode = CPCGEN_MODE_INTEL;
624d0e58ef5SRobert Mustacchi 	} else {
625d0e58ef5SRobert Mustacchi 		if (errno != ENOENT) {
626d0e58ef5SRobert Mustacchi 			err(EXIT_FAILURE, "stat(2) of %s failed unexpectedly");
627d0e58ef5SRobert Mustacchi 		}
628d0e58ef5SRobert Mustacchi 
629d0e58ef5SRobert Mustacchi 		cpcgen_mode = CPCGEN_MODE_AMD;
630d0e58ef5SRobert Mustacchi 	}
631d0e58ef5SRobert Mustacchi 
632d0e58ef5SRobert Mustacchi 	free(mappath);
633d0e58ef5SRobert Mustacchi }
634d0e58ef5SRobert Mustacchi 
635d0e58ef5SRobert Mustacchi /*
636d0e58ef5SRobert Mustacchi  * Read in all the data files that exist for AMD.
637d0e58ef5SRobert Mustacchi  *
638d0e58ef5SRobert Mustacchi  * Our family names for AMD systems are based on the family and type so a given
63931aa6202SRobert Mustacchi  * name will look like f17h_<core>_core.json.
640d0e58ef5SRobert Mustacchi  */
641d0e58ef5SRobert Mustacchi static void
642d0e58ef5SRobert Mustacchi cpcgen_read_amd(const char *datadir, const char *platform)
643d0e58ef5SRobert Mustacchi {
644d0e58ef5SRobert Mustacchi 	DIR *dir;
645d0e58ef5SRobert Mustacchi 	struct dirent *d;
646d0e58ef5SRobert Mustacchi 	const char *suffix = ".json";
647d0e58ef5SRobert Mustacchi 	const size_t slen = strlen(suffix);
648d0e58ef5SRobert Mustacchi 
649d0e58ef5SRobert Mustacchi 	if ((dir = opendir(datadir)) == NULL) {
650d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to open directory %s", datadir);
651d0e58ef5SRobert Mustacchi 	}
652d0e58ef5SRobert Mustacchi 
653d0e58ef5SRobert Mustacchi 	while ((d = readdir(dir)) != NULL) {
654d0e58ef5SRobert Mustacchi 		char *name, *c;
655d0e58ef5SRobert Mustacchi 		cpc_map_t *map;
656d0e58ef5SRobert Mustacchi 		nvlist_t *parsed;
657d0e58ef5SRobert Mustacchi 
658d0e58ef5SRobert Mustacchi 		if ((name = strdup(d->d_name)) == NULL) {
659d0e58ef5SRobert Mustacchi 			errx(EXIT_FAILURE, "ran out of memory duplicating "
660d0e58ef5SRobert Mustacchi 			    "name %s", d->d_name);
661d0e58ef5SRobert Mustacchi 		}
662d0e58ef5SRobert Mustacchi 		c = strstr(name, suffix);
663d0e58ef5SRobert Mustacchi 
664d0e58ef5SRobert Mustacchi 		if (c == NULL) {
665d0e58ef5SRobert Mustacchi 			free(name);
666d0e58ef5SRobert Mustacchi 			continue;
667d0e58ef5SRobert Mustacchi 		}
668d0e58ef5SRobert Mustacchi 
66931aa6202SRobert Mustacchi 		/*
67031aa6202SRobert Mustacchi 		 * Chop off the .json. Next, make sure we have both _ present.
67131aa6202SRobert Mustacchi 		 */
672d0e58ef5SRobert Mustacchi 		if (*(c + slen) != '\0') {
673d0e58ef5SRobert Mustacchi 			free(name);
674d0e58ef5SRobert Mustacchi 			continue;
675d0e58ef5SRobert Mustacchi 		}
676d0e58ef5SRobert Mustacchi 		*c = '\0';
67731aa6202SRobert Mustacchi 
678d0e58ef5SRobert Mustacchi 		c = strchr(name, '_');
679d0e58ef5SRobert Mustacchi 		if (c == NULL) {
68031aa6202SRobert Mustacchi 			errx(EXIT_FAILURE, "unexpected AMD JSON file name: %s",
68131aa6202SRobert Mustacchi 			    d->d_name);
68231aa6202SRobert Mustacchi 		}
68331aa6202SRobert Mustacchi 
68431aa6202SRobert Mustacchi 		c++;
68531aa6202SRobert Mustacchi 		c = strchr(c, '_');
68631aa6202SRobert Mustacchi 		if (c == NULL) {
68731aa6202SRobert Mustacchi 			errx(EXIT_FAILURE, "unexpected AMD JSON file name: %s",
68831aa6202SRobert Mustacchi 			    d->d_name);
689d0e58ef5SRobert Mustacchi 		}
690d0e58ef5SRobert Mustacchi 		*c = '\0';
691d0e58ef5SRobert Mustacchi 		c++;
692d0e58ef5SRobert Mustacchi 		if (strcmp(c, "core") != 0) {
693d0e58ef5SRobert Mustacchi 			errx(EXIT_FAILURE, "unexpected AMD JSON file name: %s",
694d0e58ef5SRobert Mustacchi 			    d->d_name);
695d0e58ef5SRobert Mustacchi 		}
696d0e58ef5SRobert Mustacchi 
697d0e58ef5SRobert Mustacchi 		if (platform != NULL && strcmp(platform, name) != 0) {
698d0e58ef5SRobert Mustacchi 			free(name);
699d0e58ef5SRobert Mustacchi 			continue;
700d0e58ef5SRobert Mustacchi 		}
701d0e58ef5SRobert Mustacchi 
702d0e58ef5SRobert Mustacchi 		if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
703d0e58ef5SRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate space for cpc "
704d0e58ef5SRobert Mustacchi 			    "file");
705d0e58ef5SRobert Mustacchi 		}
706d0e58ef5SRobert Mustacchi 
707d0e58ef5SRobert Mustacchi 		parsed = cpcgen_read_datafile(datadir, d->d_name);
708d0e58ef5SRobert Mustacchi 		if ((map->cmap_path = strdup(d->d_name)) == NULL) {
709d0e58ef5SRobert Mustacchi 			err(EXIT_FAILURE, "failed to duplicate path string");
710d0e58ef5SRobert Mustacchi 		}
711d0e58ef5SRobert Mustacchi 		map->cmap_type = CPC_FILE_CORE;
712d0e58ef5SRobert Mustacchi 		map->cmap_data = parsed;
713d0e58ef5SRobert Mustacchi 		map->cmap_name = name;
714d0e58ef5SRobert Mustacchi 		map->cmap_procs = NULL;
715d0e58ef5SRobert Mustacchi 
716d0e58ef5SRobert Mustacchi 		map->cmap_next = cpcgen_maps;
717d0e58ef5SRobert Mustacchi 		cpcgen_maps = map;
718d0e58ef5SRobert Mustacchi 	}
719d0e58ef5SRobert Mustacchi }
720d0e58ef5SRobert Mustacchi 
7217e3dbbacSRobert Mustacchi /*
7227e3dbbacSRobert Mustacchi  * Read in the mapfile.csv that is used to map between processor families and
7237e3dbbacSRobert Mustacchi  * parse this. Each line has a comma separated value.
7247e3dbbacSRobert Mustacchi  */
7257e3dbbacSRobert Mustacchi static void
726d0e58ef5SRobert Mustacchi cpcgen_read_intel(const char *datadir, const char *platform)
7277e3dbbacSRobert Mustacchi {
7287e3dbbacSRobert Mustacchi 	FILE *map;
7297e3dbbacSRobert Mustacchi 	char *mappath, *last;
7307e3dbbacSRobert Mustacchi 	char *data = NULL;
7317e3dbbacSRobert Mustacchi 	size_t datalen = 0;
7327e3dbbacSRobert Mustacchi 	uint_t lineno;
7337e3dbbacSRobert Mustacchi 
734d0e58ef5SRobert Mustacchi 	if (asprintf(&mappath, "%s/%s", datadir, cpcgen_intel_mapfile) == -1) {
7357e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct path to mapfile");
7367e3dbbacSRobert Mustacchi 	}
7377e3dbbacSRobert Mustacchi 
7387e3dbbacSRobert Mustacchi 	if ((map = fopen(mappath, "r")) == NULL) {
7397e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open data mapfile %s", mappath);
7407e3dbbacSRobert Mustacchi 	}
7417e3dbbacSRobert Mustacchi 
7427e3dbbacSRobert Mustacchi 	lineno = 0;
7437e3dbbacSRobert Mustacchi 	while (getline(&data, &datalen, map) != -1) {
7447e3dbbacSRobert Mustacchi 		char *fstr, *path, *tstr;
7457e3dbbacSRobert Mustacchi 		const char *name;
746c18e9bc3SRobert Mustacchi 		uint_t family, model, nsteps;
747c18e9bc3SRobert Mustacchi 		uint_t steppings[CPROC_MAX_STEPPINGS];
748c18e9bc3SRobert Mustacchi 
7497e3dbbacSRobert Mustacchi 		cpc_type_t type;
7507e3dbbacSRobert Mustacchi 		cpc_map_t *map;
7517e3dbbacSRobert Mustacchi 		cpc_proc_t *proc;
7527e3dbbacSRobert Mustacchi 
7537e3dbbacSRobert Mustacchi 		/*
7547e3dbbacSRobert Mustacchi 		 * The first line contains the header:
7557e3dbbacSRobert Mustacchi 		 * Family-model,Version,Filename,EventType
7567e3dbbacSRobert Mustacchi 		 */
7577e3dbbacSRobert Mustacchi 		lineno++;
7587e3dbbacSRobert Mustacchi 		if (lineno == 1) {
7597e3dbbacSRobert Mustacchi 			continue;
7607e3dbbacSRobert Mustacchi 		}
7617e3dbbacSRobert Mustacchi 
7627e3dbbacSRobert Mustacchi 		if ((fstr = strtok_r(data, ",", &last)) == NULL ||
7637e3dbbacSRobert Mustacchi 		    strtok_r(NULL, ",", &last) == NULL ||
7647e3dbbacSRobert Mustacchi 		    (path = strtok_r(NULL, ",", &last)) == NULL ||
7657e3dbbacSRobert Mustacchi 		    (tstr = strtok_r(NULL, "\n", &last)) == NULL) {
7667e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to parse mapfile line "
7677e3dbbacSRobert Mustacchi 			    "%u in %s", lineno, mappath);
7687e3dbbacSRobert Mustacchi 		}
7697e3dbbacSRobert Mustacchi 
770c18e9bc3SRobert Mustacchi 		cpcgen_parse_model(fstr, &family, &model, &nsteps, steppings);
7717e3dbbacSRobert Mustacchi 
7727e3dbbacSRobert Mustacchi 		if (strcmp(tstr, "core") == 0) {
7737e3dbbacSRobert Mustacchi 			type = CPC_FILE_CORE;
7747e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "offcore") == 0) {
7757e3dbbacSRobert Mustacchi 			type = CPC_FILE_OFF_CORE;
7767e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore") == 0) {
7777e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE;
7787e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "fp_arith_inst") == 0) {
7797e3dbbacSRobert Mustacchi 			type = CPC_FILE_FP_MATH;
7807e3dbbacSRobert Mustacchi 		} else if (strcmp(tstr, "uncore experimental") == 0) {
7817e3dbbacSRobert Mustacchi 			type = CPC_FILE_UNCORE_EXP;
7827e3dbbacSRobert Mustacchi 		} else {
7837e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "unknown file type \"%s\" on line "
7847e3dbbacSRobert Mustacchi 			    "%u", tstr, lineno);
7857e3dbbacSRobert Mustacchi 		}
7867e3dbbacSRobert Mustacchi 
7877e3dbbacSRobert Mustacchi 		if ((name = cpcgen_use_arch(path, type, platform)) == NULL)
7887e3dbbacSRobert Mustacchi 			continue;
7897e3dbbacSRobert Mustacchi 
7907e3dbbacSRobert Mustacchi 		if ((map = cpcgen_map_lookup(path)) == NULL) {
7917e3dbbacSRobert Mustacchi 			nvlist_t *parsed;
7927e3dbbacSRobert Mustacchi 
7937e3dbbacSRobert Mustacchi 			parsed = cpcgen_read_datafile(datadir, path);
7947e3dbbacSRobert Mustacchi 
7957e3dbbacSRobert Mustacchi 			if ((map = calloc(1, sizeof (cpc_map_t))) == NULL) {
7967e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to allocate space "
7977e3dbbacSRobert Mustacchi 				    "for cpc file");
7987e3dbbacSRobert Mustacchi 			}
7997e3dbbacSRobert Mustacchi 
8007e3dbbacSRobert Mustacchi 			if ((map->cmap_path = strdup(path)) == NULL) {
8017e3dbbacSRobert Mustacchi 				err(EXIT_FAILURE, "failed to duplicate path "
8027e3dbbacSRobert Mustacchi 				    "string");
8037e3dbbacSRobert Mustacchi 			}
8047e3dbbacSRobert Mustacchi 
8057e3dbbacSRobert Mustacchi 			map->cmap_type = type;
8067e3dbbacSRobert Mustacchi 			map->cmap_data = parsed;
8077e3dbbacSRobert Mustacchi 			map->cmap_name = name;
808c18e9bc3SRobert Mustacchi 			map->cmap_procs = NULL;
809d0e58ef5SRobert Mustacchi 
810d0e58ef5SRobert Mustacchi 			map->cmap_next = cpcgen_maps;
8117e3dbbacSRobert Mustacchi 			cpcgen_maps = map;
8127e3dbbacSRobert Mustacchi 		}
8137e3dbbacSRobert Mustacchi 
814c18e9bc3SRobert Mustacchi 		if ((proc = calloc(1, sizeof (cpc_proc_t))) == NULL) {
8157e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to allocate memory for "
8167e3dbbacSRobert Mustacchi 			    "family and model tracking");
8177e3dbbacSRobert Mustacchi 		}
8187e3dbbacSRobert Mustacchi 
8197e3dbbacSRobert Mustacchi 		proc->cproc_family = family;
8207e3dbbacSRobert Mustacchi 		proc->cproc_model = model;
821c18e9bc3SRobert Mustacchi 		proc->cproc_nsteps = nsteps;
822c18e9bc3SRobert Mustacchi 		if (nsteps > 0) {
823c18e9bc3SRobert Mustacchi 			bcopy(steppings, proc->cproc_steppings,
824c18e9bc3SRobert Mustacchi 			    sizeof (steppings));
825c18e9bc3SRobert Mustacchi 		}
8267e3dbbacSRobert Mustacchi 		proc->cproc_next = map->cmap_procs;
8277e3dbbacSRobert Mustacchi 		map->cmap_procs = proc;
8287e3dbbacSRobert Mustacchi 	}
8297e3dbbacSRobert Mustacchi 
8307e3dbbacSRobert Mustacchi 	if (errno != 0 || ferror(map)) {
8317e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to read %s", mappath);
8327e3dbbacSRobert Mustacchi 	}
8337e3dbbacSRobert Mustacchi 
8347e3dbbacSRobert Mustacchi 	if (fclose(map) == EOF) {
8357e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to close %s", mappath);
8367e3dbbacSRobert Mustacchi 	}
8377e3dbbacSRobert Mustacchi 	free(data);
8387e3dbbacSRobert Mustacchi 	free(mappath);
8397e3dbbacSRobert Mustacchi }
8407e3dbbacSRobert Mustacchi 
8417e3dbbacSRobert Mustacchi static char *
842d0e58ef5SRobert Mustacchi cpcgen_manual_intel_name(cpc_map_t *map)
8437e3dbbacSRobert Mustacchi {
8447e3dbbacSRobert Mustacchi 	char *name;
8457e3dbbacSRobert Mustacchi 
8467e3dbbacSRobert Mustacchi 	if (asprintf(&name, "%s_events.3cpc", map->cmap_name) == -1) {
8477e3dbbacSRobert Mustacchi 		warn("failed to assemble manual page name for %s",
8487e3dbbacSRobert Mustacchi 		    map->cmap_path);
8497e3dbbacSRobert Mustacchi 		return (NULL);
8507e3dbbacSRobert Mustacchi 	}
8517e3dbbacSRobert Mustacchi 
8527e3dbbacSRobert Mustacchi 	return (name);
8537e3dbbacSRobert Mustacchi }
8547e3dbbacSRobert Mustacchi 
8557e3dbbacSRobert Mustacchi static boolean_t
856d0e58ef5SRobert Mustacchi cpcgen_manual_intel_file_before(FILE *f, cpc_map_t *map)
8577e3dbbacSRobert Mustacchi {
8587e3dbbacSRobert Mustacchi 	size_t i;
8597e3dbbacSRobert Mustacchi 	char *upper;
8607e3dbbacSRobert Mustacchi 	cpc_proc_t *proc;
8617e3dbbacSRobert Mustacchi 
8627e3dbbacSRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
8637e3dbbacSRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
8647e3dbbacSRobert Mustacchi 		return (B_FALSE);
8657e3dbbacSRobert Mustacchi 	}
8667e3dbbacSRobert Mustacchi 
8677e3dbbacSRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
8687e3dbbacSRobert Mustacchi 		upper[i] = toupper(upper[i]);
8697e3dbbacSRobert Mustacchi 	}
8707e3dbbacSRobert Mustacchi 
871d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_intel_intel_header, map->cmap_path, upper,
8727e3dbbacSRobert Mustacchi 	    map->cmap_name) == -1) {
8737e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
8747e3dbbacSRobert Mustacchi 		    map->cmap_name);
8757e3dbbacSRobert Mustacchi 		free(upper);
8767e3dbbacSRobert Mustacchi 		return (B_FALSE);
8777e3dbbacSRobert Mustacchi 	}
878d0e58ef5SRobert Mustacchi 	free(upper);
8797e3dbbacSRobert Mustacchi 
8807e3dbbacSRobert Mustacchi 	for (proc = map->cmap_procs; proc != NULL; proc = proc->cproc_next) {
881c18e9bc3SRobert Mustacchi 		if (proc->cproc_nsteps > 0) {
882c18e9bc3SRobert Mustacchi 			uint_t step;
883c18e9bc3SRobert Mustacchi 
884c18e9bc3SRobert Mustacchi 			for (step = 0; step < proc->cproc_nsteps; step++) {
885c18e9bc3SRobert Mustacchi 				if (fprintf(f, ".It\n.Sy Family 0x%x, Model "
886c18e9bc3SRobert Mustacchi 				    "0x%x, Stepping 0x%x\n",
887c18e9bc3SRobert Mustacchi 				    proc->cproc_family, proc->cproc_model,
888c18e9bc3SRobert Mustacchi 				    proc->cproc_steppings[step]) == -1) {
889c18e9bc3SRobert Mustacchi 					warn("failed to write out model "
890c18e9bc3SRobert Mustacchi 					    "information for %s",
891c18e9bc3SRobert Mustacchi 					    map->cmap_name);
892c18e9bc3SRobert Mustacchi 					return (B_FALSE);
893c18e9bc3SRobert Mustacchi 				}
894c18e9bc3SRobert Mustacchi 			}
895c18e9bc3SRobert Mustacchi 		} else {
896c18e9bc3SRobert Mustacchi 			if (fprintf(f, ".It\n.Sy Family 0x%x, Model 0x%x\n",
897c18e9bc3SRobert Mustacchi 			    proc->cproc_family, proc->cproc_model) == -1) {
898c18e9bc3SRobert Mustacchi 				warn("failed to write out model information "
899c18e9bc3SRobert Mustacchi 				    "for %s", map->cmap_name);
900c18e9bc3SRobert Mustacchi 				return (B_FALSE);
901c18e9bc3SRobert Mustacchi 			}
9027e3dbbacSRobert Mustacchi 		}
9037e3dbbacSRobert Mustacchi 	}
9047e3dbbacSRobert Mustacchi 
905d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_intel_data) == -1) {
9067e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
9077e3dbbacSRobert Mustacchi 		    map->cmap_name);
9087e3dbbacSRobert Mustacchi 		return (B_FALSE);
9097e3dbbacSRobert Mustacchi 	}
9107e3dbbacSRobert Mustacchi 
9117e3dbbacSRobert Mustacchi 	return (B_TRUE);
9127e3dbbacSRobert Mustacchi }
9137e3dbbacSRobert Mustacchi 
9147e3dbbacSRobert Mustacchi static boolean_t
915d0e58ef5SRobert Mustacchi cpcgen_manual_intel_file_after(FILE *f, cpc_map_t *map)
9167e3dbbacSRobert Mustacchi {
917d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_intel_trailer) == -1) {
9187e3dbbacSRobert Mustacchi 		warn("failed to write out manual header for %s",
9197e3dbbacSRobert Mustacchi 		    map->cmap_name);
9207e3dbbacSRobert Mustacchi 		return (B_FALSE);
9217e3dbbacSRobert Mustacchi 	}
9227e3dbbacSRobert Mustacchi 
9237e3dbbacSRobert Mustacchi 	return (B_TRUE);
9247e3dbbacSRobert Mustacchi }
9257e3dbbacSRobert Mustacchi 
9267e3dbbacSRobert Mustacchi static boolean_t
927d0e58ef5SRobert Mustacchi cpcgen_manual_intel_event(FILE *f, nvlist_t *nvl, const char *path,
928d0e58ef5SRobert Mustacchi     uint32_t ent)
9297e3dbbacSRobert Mustacchi {
9307e3dbbacSRobert Mustacchi 	char *event, *lname, *brief = NULL, *public = NULL, *errata = NULL;
9317e3dbbacSRobert Mustacchi 	size_t i;
9327e3dbbacSRobert Mustacchi 
9337e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
9347e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
9357e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
9367e3dbbacSRobert Mustacchi 		return (B_FALSE);
9377e3dbbacSRobert Mustacchi 	}
9387e3dbbacSRobert Mustacchi 
9397e3dbbacSRobert Mustacchi 	/*
9407e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
9417e3dbbacSRobert Mustacchi 	 */
9427e3dbbacSRobert Mustacchi 	if ((lname = strdup(event)) == NULL) {
9437e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", event);
9447e3dbbacSRobert Mustacchi 	}
9457e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
9467e3dbbacSRobert Mustacchi 		lname[i] = tolower(event[i]);
9477e3dbbacSRobert Mustacchi 	}
9487e3dbbacSRobert Mustacchi 
9497e3dbbacSRobert Mustacchi 	/*
9507e3dbbacSRobert Mustacchi 	 * Try to get the other event fields, but if they're not there, don't
9517e3dbbacSRobert Mustacchi 	 * worry about it.
9527e3dbbacSRobert Mustacchi 	 */
9537e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "BriefDescription", &brief);
9547e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "PublicDescription", &public);
9557e3dbbacSRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "Errata", &errata);
9567e3dbbacSRobert Mustacchi 	if (errata != NULL && (strcmp(errata, "0") == 0 ||
9577e3dbbacSRobert Mustacchi 	    strcmp(errata, "null") == 0)) {
9587e3dbbacSRobert Mustacchi 		errata = NULL;
9597e3dbbacSRobert Mustacchi 	}
9607e3dbbacSRobert Mustacchi 
9617e3dbbacSRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", lname) == -1) {
962d0e58ef5SRobert Mustacchi 		warn("failed to write out event entry %s", event);
9637e3dbbacSRobert Mustacchi 		free(lname);
9647e3dbbacSRobert Mustacchi 		return (B_FALSE);
9657e3dbbacSRobert Mustacchi 	}
9667e3dbbacSRobert Mustacchi 
9677e3dbbacSRobert Mustacchi 	if (public != NULL) {
9687e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", public) == -1) {
969d0e58ef5SRobert Mustacchi 			warn("failed to write out event entry %s", event);
9707e3dbbacSRobert Mustacchi 			free(lname);
9717e3dbbacSRobert Mustacchi 			return (B_FALSE);
9727e3dbbacSRobert Mustacchi 		}
9737e3dbbacSRobert Mustacchi 	} else if (brief != NULL) {
9747e3dbbacSRobert Mustacchi 		if (fprintf(f, "%s\n", brief) == -1) {
975d0e58ef5SRobert Mustacchi 			warn("failed to write out event entry %s", event);
9767e3dbbacSRobert Mustacchi 			free(lname);
9777e3dbbacSRobert Mustacchi 			return (B_FALSE);
9787e3dbbacSRobert Mustacchi 		}
9797e3dbbacSRobert Mustacchi 	}
9807e3dbbacSRobert Mustacchi 
9817e3dbbacSRobert Mustacchi 	if (errata != NULL) {
9827e3dbbacSRobert Mustacchi 		if (fprintf(f, ".Pp\nThe following errata may apply to this: "
9837e3dbbacSRobert Mustacchi 		    "%s\n", errata) == -1) {
9847e3dbbacSRobert Mustacchi 
985d0e58ef5SRobert Mustacchi 			warn("failed to write out event entry %s", event);
9867e3dbbacSRobert Mustacchi 			free(lname);
9877e3dbbacSRobert Mustacchi 			return (B_FALSE);
9887e3dbbacSRobert Mustacchi 		}
9897e3dbbacSRobert Mustacchi 	}
9907e3dbbacSRobert Mustacchi 
9917e3dbbacSRobert Mustacchi 	free(lname);
9927e3dbbacSRobert Mustacchi 	return (B_TRUE);
9937e3dbbacSRobert Mustacchi }
9947e3dbbacSRobert Mustacchi 
9957e3dbbacSRobert Mustacchi static char *
996d0e58ef5SRobert Mustacchi cpcgen_cfile_intel_name(cpc_map_t *map)
9977e3dbbacSRobert Mustacchi {
9987e3dbbacSRobert Mustacchi 	char *name;
9997e3dbbacSRobert Mustacchi 
10007e3dbbacSRobert Mustacchi 	if (asprintf(&name, "core_pcbe_%s.c", map->cmap_name) == -1) {
10017e3dbbacSRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
10027e3dbbacSRobert Mustacchi 		return (NULL);
10037e3dbbacSRobert Mustacchi 	}
10047e3dbbacSRobert Mustacchi 
10057e3dbbacSRobert Mustacchi 	return (name);
10067e3dbbacSRobert Mustacchi }
10077e3dbbacSRobert Mustacchi 
10087e3dbbacSRobert Mustacchi static boolean_t
1009d0e58ef5SRobert Mustacchi cpcgen_cfile_intel_before(FILE *f, cpc_map_t *map)
10107e3dbbacSRobert Mustacchi {
1011d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_intel_header, map->cmap_path) == -1) {
10127e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
10137e3dbbacSRobert Mustacchi 		    map->cmap_path);
10147e3dbbacSRobert Mustacchi 		return (B_FALSE);
10157e3dbbacSRobert Mustacchi 	}
10167e3dbbacSRobert Mustacchi 
1017d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_intel_table_start, map->cmap_name) == -1) {
10187e3dbbacSRobert Mustacchi 		warn("failed to write header to temporary file for %s",
10197e3dbbacSRobert Mustacchi 		    map->cmap_path);
10207e3dbbacSRobert Mustacchi 		return (B_FALSE);
10217e3dbbacSRobert Mustacchi 	}
10227e3dbbacSRobert Mustacchi 
10237e3dbbacSRobert Mustacchi 	return (B_TRUE);
10247e3dbbacSRobert Mustacchi }
10257e3dbbacSRobert Mustacchi 
10267e3dbbacSRobert Mustacchi static boolean_t
1027d0e58ef5SRobert Mustacchi cpcgen_cfile_intel_after(FILE *f, cpc_map_t *map)
10287e3dbbacSRobert Mustacchi {
1029d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_intel_table_end) == -1) {
10307e3dbbacSRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
10317e3dbbacSRobert Mustacchi 		    map->cmap_path);
10327e3dbbacSRobert Mustacchi 		return (B_FALSE);
10337e3dbbacSRobert Mustacchi 	}
10347e3dbbacSRobert Mustacchi 
10357e3dbbacSRobert Mustacchi 	return (B_TRUE);
10367e3dbbacSRobert Mustacchi }
10377e3dbbacSRobert Mustacchi 
10387e3dbbacSRobert Mustacchi static boolean_t
1039d0e58ef5SRobert Mustacchi cpcgen_cfile_intel_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
10407e3dbbacSRobert Mustacchi {
10417e3dbbacSRobert Mustacchi 	char *ecode, *umask, *name, *counter, *lname, *cmask;
10427e3dbbacSRobert Mustacchi 	size_t i;
10437e3dbbacSRobert Mustacchi 
10447e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &name) != 0) {
10457e3dbbacSRobert Mustacchi 		warnx("Found event without 'EventName' property "
10467e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
10477e3dbbacSRobert Mustacchi 		return (B_FALSE);
10487e3dbbacSRobert Mustacchi 	}
10497e3dbbacSRobert Mustacchi 
10507e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
10517e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
10527e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0) {
10537e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, missing "
10547e3dbbacSRobert Mustacchi 		    "required properties for C file translation",
10557e3dbbacSRobert Mustacchi 		    name, ent, path);
10567e3dbbacSRobert Mustacchi 		return (B_FALSE);
10577e3dbbacSRobert Mustacchi 	}
10587e3dbbacSRobert Mustacchi 
10597e3dbbacSRobert Mustacchi 	/*
10607e3dbbacSRobert Mustacchi 	 * While we could try and parse the counters manually, just do this the
10617e3dbbacSRobert Mustacchi 	 * max power way for now based on all possible values.
10627e3dbbacSRobert Mustacchi 	 */
10637e3dbbacSRobert Mustacchi 	if (strcmp(counter, "0") == 0 || strcmp(counter, "0,") == 0) {
10647e3dbbacSRobert Mustacchi 		cmask = "C0";
10657e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1") == 0) {
10667e3dbbacSRobert Mustacchi 		cmask = "C1";
10677e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2") == 0) {
10687e3dbbacSRobert Mustacchi 		cmask = "C2";
10697e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "3") == 0) {
10707e3dbbacSRobert Mustacchi 		cmask = "C3";
10717e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1") == 0) {
10727e3dbbacSRobert Mustacchi 		cmask = "C0|C1";
10737e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2") == 0) {
10747e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2";
10757e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3") == 0) {
10767e3dbbacSRobert Mustacchi 		cmask = "C0|C1|C2|C3";
1077*43449cdcSRobert Mustacchi 	} else if (strcmp(counter, "0,1,2,3,4,5,6,7") == 0) {
1078*43449cdcSRobert Mustacchi 		/*
1079*43449cdcSRobert Mustacchi 		 * We don't support the larger number of counters on some
1080*43449cdcSRobert Mustacchi 		 * platforms right now, so just truncate it to the supported
1081*43449cdcSRobert Mustacchi 		 * set.
1082*43449cdcSRobert Mustacchi 		 */
1083*43449cdcSRobert Mustacchi 		cmask = "C0|C1|C2|C3";
10847e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "0,2,3") == 0) {
10857e3dbbacSRobert Mustacchi 		cmask = "C0|C2|C3";
10867e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "1,2,3") == 0) {
10877e3dbbacSRobert Mustacchi 		cmask = "C1|C2|C3";
10887e3dbbacSRobert Mustacchi 	} else if (strcmp(counter, "2,3") == 0) {
10897e3dbbacSRobert Mustacchi 		cmask = "C2|C3";
10907e3dbbacSRobert Mustacchi 	} else {
10917e3dbbacSRobert Mustacchi 		warnx("event %s (index %u) from %s, has unknown "
10927e3dbbacSRobert Mustacchi 		    "counter value \"%s\"", name, ent, path, counter);
10937e3dbbacSRobert Mustacchi 		return (B_FALSE);
10947e3dbbacSRobert Mustacchi 	}
10957e3dbbacSRobert Mustacchi 
10967e3dbbacSRobert Mustacchi 
10977e3dbbacSRobert Mustacchi 	/*
10987e3dbbacSRobert Mustacchi 	 * Intel uses capital names. CPC historically uses lower case names.
10997e3dbbacSRobert Mustacchi 	 */
11007e3dbbacSRobert Mustacchi 	if ((lname = strdup(name)) == NULL) {
11017e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to duplicate event name %s", name);
11027e3dbbacSRobert Mustacchi 	}
11037e3dbbacSRobert Mustacchi 	for (i = 0; lname[i] != '\0'; i++) {
11047e3dbbacSRobert Mustacchi 		lname[i] = tolower(name[i]);
11057e3dbbacSRobert Mustacchi 	}
11067e3dbbacSRobert Mustacchi 
11077e3dbbacSRobert Mustacchi 	if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask, cmask,
11087e3dbbacSRobert Mustacchi 	    lname) == -1) {
11097e3dbbacSRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
11107e3dbbacSRobert Mustacchi 		free(lname);
11117e3dbbacSRobert Mustacchi 		return (B_FALSE);
11127e3dbbacSRobert Mustacchi 	}
11137e3dbbacSRobert Mustacchi 
11147e3dbbacSRobert Mustacchi 	free(lname);
11157e3dbbacSRobert Mustacchi 
11167e3dbbacSRobert Mustacchi 	/*
11177e3dbbacSRobert Mustacchi 	 * Check if we have any PAPI aliases.
11187e3dbbacSRobert Mustacchi 	 */
1119d0e58ef5SRobert Mustacchi 	for (i = 0; cpcgen_intel_papi_map[i].cpapi_intc != NULL; i++) {
1120d0e58ef5SRobert Mustacchi 		if (strcmp(name, cpcgen_intel_papi_map[i].cpapi_intc) != 0)
11217e3dbbacSRobert Mustacchi 			continue;
11227e3dbbacSRobert Mustacchi 
11237e3dbbacSRobert Mustacchi 		if (fprintf(f, "\t{ %s, %s, %s, \"%s\" },\n", ecode, umask,
1124d0e58ef5SRobert Mustacchi 		    cmask, cpcgen_intel_papi_map[i].cpapi_papi) == -1) {
11257e3dbbacSRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
11267e3dbbacSRobert Mustacchi 			    path);
11277e3dbbacSRobert Mustacchi 			return (B_FALSE);
11287e3dbbacSRobert Mustacchi 		}
11297e3dbbacSRobert Mustacchi 	}
11307e3dbbacSRobert Mustacchi 
11317e3dbbacSRobert Mustacchi 	return (B_TRUE);
11327e3dbbacSRobert Mustacchi }
11337e3dbbacSRobert Mustacchi 
1134c18e9bc3SRobert Mustacchi static boolean_t
1135c18e9bc3SRobert Mustacchi cpcgen_generate_map(FILE *f, cpc_map_t *map, boolean_t start)
1136c18e9bc3SRobert Mustacchi {
1137c18e9bc3SRobert Mustacchi 	cpc_proc_t *p;
1138c18e9bc3SRobert Mustacchi 
1139c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t%sif (", start ? "" : "} else ") == -1) {
1140c18e9bc3SRobert Mustacchi 		return (B_FALSE);
1141c18e9bc3SRobert Mustacchi 	}
1142c18e9bc3SRobert Mustacchi 
1143c18e9bc3SRobert Mustacchi 	for (p = map->cmap_procs; p != NULL; p = p->cproc_next) {
1144c18e9bc3SRobert Mustacchi 		/*
1145c18e9bc3SRobert Mustacchi 		 * Make sure the line is padded so the generated C code looks
1146c18e9bc3SRobert Mustacchi 		 * like reasonable C style.
1147c18e9bc3SRobert Mustacchi 		 */
1148c18e9bc3SRobert Mustacchi 		if (p != map->cmap_procs) {
1149c18e9bc3SRobert Mustacchi 			if (fputs("\t    ", f) == -1) {
1150c18e9bc3SRobert Mustacchi 				return (B_FALSE);
1151c18e9bc3SRobert Mustacchi 			}
1152c18e9bc3SRobert Mustacchi 		}
1153c18e9bc3SRobert Mustacchi 
1154c18e9bc3SRobert Mustacchi 		if (p->cproc_nsteps > 0) {
1155c18e9bc3SRobert Mustacchi 			uint_t i;
1156c18e9bc3SRobert Mustacchi 
1157c18e9bc3SRobert Mustacchi 			if (fprintf(f, "(model == 0x%x &&\n\t    (",
1158c18e9bc3SRobert Mustacchi 			    p->cproc_model) == -1) {
1159c18e9bc3SRobert Mustacchi 				return (B_FALSE);
1160c18e9bc3SRobert Mustacchi 			}
1161c18e9bc3SRobert Mustacchi 
1162c18e9bc3SRobert Mustacchi 			for (i = 0; i < p->cproc_nsteps; i++) {
1163c18e9bc3SRobert Mustacchi 				if (fprintf(f, "stepping == 0x%x%s",
1164c18e9bc3SRobert Mustacchi 				    p->cproc_steppings[i],
1165c18e9bc3SRobert Mustacchi 				    i + 1 != p->cproc_nsteps ?
1166c18e9bc3SRobert Mustacchi 				    " ||\n\t    " : "") == -1) {
1167c18e9bc3SRobert Mustacchi 					return (B_FALSE);
1168c18e9bc3SRobert Mustacchi 				}
1169c18e9bc3SRobert Mustacchi 			}
1170c18e9bc3SRobert Mustacchi 
1171c18e9bc3SRobert Mustacchi 			if (fputs("))", f) == -1) {
1172c18e9bc3SRobert Mustacchi 				return (B_FALSE);
1173c18e9bc3SRobert Mustacchi 			}
1174c18e9bc3SRobert Mustacchi 		} else if (fprintf(f, "model == 0x%x", p->cproc_model) == -1) {
1175c18e9bc3SRobert Mustacchi 			return (B_FALSE);
1176c18e9bc3SRobert Mustacchi 		}
1177c18e9bc3SRobert Mustacchi 
1178c18e9bc3SRobert Mustacchi 		if (fprintf(f, "%s\n",
1179c18e9bc3SRobert Mustacchi 		    p->cproc_next != NULL ? " ||" : ") {") == -1) {
1180c18e9bc3SRobert Mustacchi 			return (B_FALSE);
1181c18e9bc3SRobert Mustacchi 		}
1182c18e9bc3SRobert Mustacchi 	}
1183c18e9bc3SRobert Mustacchi 
1184c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t\t\treturn (pcbe_core_events_%s);\n",
1185c18e9bc3SRobert Mustacchi 	    map->cmap_name) == -1) {
1186c18e9bc3SRobert Mustacchi 		return (B_FALSE);
1187c18e9bc3SRobert Mustacchi 	}
1188c18e9bc3SRobert Mustacchi 
1189c18e9bc3SRobert Mustacchi 	return (B_TRUE);
1190c18e9bc3SRobert Mustacchi }
1191c18e9bc3SRobert Mustacchi 
1192d0e58ef5SRobert Mustacchi /*
1193d0e58ef5SRobert Mustacchi  * This is a wrapper around unlinkat that makes sure that we don't clobber
1194d0e58ef5SRobert Mustacchi  * errno, which is used for properly printing out error messages below.
1195d0e58ef5SRobert Mustacchi  */
1196d0e58ef5SRobert Mustacchi static void
1197d0e58ef5SRobert Mustacchi cpcgen_remove_tmpfile(int dirfd, const char *path)
1198d0e58ef5SRobert Mustacchi {
1199d0e58ef5SRobert Mustacchi 	int e = errno;
1200d0e58ef5SRobert Mustacchi 	(void) unlinkat(dirfd, path, 0);
1201d0e58ef5SRobert Mustacchi 	errno = e;
1202d0e58ef5SRobert Mustacchi }
1203d0e58ef5SRobert Mustacchi 
12047e3dbbacSRobert Mustacchi /*
12057e3dbbacSRobert Mustacchi  * Generate a header file that declares all of these arrays and provide a map
12067e3dbbacSRobert Mustacchi  * for models to the corresponding table to use.
12077e3dbbacSRobert Mustacchi  */
12087e3dbbacSRobert Mustacchi static void
1209d0e58ef5SRobert Mustacchi cpcgen_common_intel_files(int dirfd)
12107e3dbbacSRobert Mustacchi {
12117e3dbbacSRobert Mustacchi 	const char *fname = "core_pcbe_cpcgen.h";
12127e3dbbacSRobert Mustacchi 	char *tmpname;
12137e3dbbacSRobert Mustacchi 	int fd;
12147e3dbbacSRobert Mustacchi 	FILE *f;
12157e3dbbacSRobert Mustacchi 	cpc_map_t *map;
12167e3dbbacSRobert Mustacchi 
12177e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
12187e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
12197e3dbbacSRobert Mustacchi 	}
12207e3dbbacSRobert Mustacchi 
12217e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
12227e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
12237e3dbbacSRobert Mustacchi 		    tmpname);
12247e3dbbacSRobert Mustacchi 	}
12257e3dbbacSRobert Mustacchi 
12267e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
1227d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12287e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
12297e3dbbacSRobert Mustacchi 	}
12307e3dbbacSRobert Mustacchi 
1231d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_intel_header, cpcgen_intel_mapfile) == -1) {
1232d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12337e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
12347e3dbbacSRobert Mustacchi 		    "for %s", fname);
12357e3dbbacSRobert Mustacchi 	}
12367e3dbbacSRobert Mustacchi 
12377e3dbbacSRobert Mustacchi 	if (fprintf(f, "#ifndef _CORE_PCBE_CPCGEN_H\n"
12387e3dbbacSRobert Mustacchi 	    "#define\t_CORE_PCBE_CPCGEN_H\n"
12397e3dbbacSRobert Mustacchi 	    "\n"
12407e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
12417e3dbbacSRobert Mustacchi 	    "extern \"C\" {\n"
12427e3dbbacSRobert Mustacchi 	    "#endif\n"
12437e3dbbacSRobert Mustacchi 	    "\n"
1244c18e9bc3SRobert Mustacchi 	    "extern const struct events_table_t *core_cpcgen_table(uint_t, "
1245c18e9bc3SRobert Mustacchi 	    "uint_t);\n"
12467e3dbbacSRobert Mustacchi 	    "\n") == -1) {
1247d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12487e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
12497e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
12507e3dbbacSRobert Mustacchi 	}
12517e3dbbacSRobert Mustacchi 
12527e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
12537e3dbbacSRobert Mustacchi 		if (fprintf(f, "extern const struct events_table_t "
12547e3dbbacSRobert Mustacchi 		    "pcbe_core_events_%s[];\n", map->cmap_name) == -1) {
1255d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
12567e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write entry to "
12577e3dbbacSRobert Mustacchi 			    "temporary file for %s", fname);
12587e3dbbacSRobert Mustacchi 		}
12597e3dbbacSRobert Mustacchi 	}
12607e3dbbacSRobert Mustacchi 
12617e3dbbacSRobert Mustacchi 	if (fprintf(f, "\n"
12627e3dbbacSRobert Mustacchi 	    "#ifdef __cplusplus\n"
12637e3dbbacSRobert Mustacchi 	    "}\n"
12647e3dbbacSRobert Mustacchi 	    "#endif\n"
12657e3dbbacSRobert Mustacchi 	    "\n"
12667e3dbbacSRobert Mustacchi 	    "#endif /* _CORE_PCBE_CPCGEN_H */\n") == -1) {
1267d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12687e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
12697e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
12707e3dbbacSRobert Mustacchi 	}
12717e3dbbacSRobert Mustacchi 
12727e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
1273d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12747e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
12757e3dbbacSRobert Mustacchi 	}
12767e3dbbacSRobert Mustacchi 
12777e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
12787e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
12797e3dbbacSRobert Mustacchi 		    tmpname);
12807e3dbbacSRobert Mustacchi 	}
12817e3dbbacSRobert Mustacchi 
12827e3dbbacSRobert Mustacchi 	free(tmpname);
12837e3dbbacSRobert Mustacchi 
12847e3dbbacSRobert Mustacchi 	/* Now again for the .c file. */
12857e3dbbacSRobert Mustacchi 	fname = "core_pcbe_cpcgen.c";
12867e3dbbacSRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
12877e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
12887e3dbbacSRobert Mustacchi 	}
12897e3dbbacSRobert Mustacchi 
12907e3dbbacSRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
12917e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
12927e3dbbacSRobert Mustacchi 		    tmpname);
12937e3dbbacSRobert Mustacchi 	}
12947e3dbbacSRobert Mustacchi 
12957e3dbbacSRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
1296d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
12977e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
12987e3dbbacSRobert Mustacchi 	}
12997e3dbbacSRobert Mustacchi 
1300d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_intel_header, cpcgen_intel_mapfile) == -1) {
1301d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
13027e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to temporary file "
13037e3dbbacSRobert Mustacchi 		    "for %s", fname);
13047e3dbbacSRobert Mustacchi 	}
13057e3dbbacSRobert Mustacchi 
13067e3dbbacSRobert Mustacchi 	if (fprintf(f, "#include <core_pcbe_table.h>\n"
13077e3dbbacSRobert Mustacchi 	    "#include <sys/null.h>\n"
13087e3dbbacSRobert Mustacchi 	    "#include \"core_pcbe_cpcgen.h\"\n"
13097e3dbbacSRobert Mustacchi 	    "\n"
13107e3dbbacSRobert Mustacchi 	    "const struct events_table_t *\n"
1311c18e9bc3SRobert Mustacchi 	    "core_cpcgen_table(uint_t model, uint_t stepping)\n"
1312c18e9bc3SRobert Mustacchi 	    "{\n") == -1) {
1313d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
13147e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
13157e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
13167e3dbbacSRobert Mustacchi 	}
13177e3dbbacSRobert Mustacchi 
13187e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1319c18e9bc3SRobert Mustacchi 		if (!cpcgen_generate_map(f, map, map == cpcgen_maps)) {
1320d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
1321c18e9bc3SRobert Mustacchi 			errx(EXIT_FAILURE, "failed to write to temporary "
1322c18e9bc3SRobert Mustacchi 			    "file for %s", fname);
13237e3dbbacSRobert Mustacchi 		}
13247e3dbbacSRobert Mustacchi 	}
13257e3dbbacSRobert Mustacchi 
1326c18e9bc3SRobert Mustacchi 	if (fprintf(f, "\t} else {\n"
13277e3dbbacSRobert Mustacchi 	    "\t\t\treturn (NULL);\n"
13287e3dbbacSRobert Mustacchi 	    "\t}\n"
13297e3dbbacSRobert Mustacchi 	    "}\n") == -1) {
1330d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
13317e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "failed to write header to "
13327e3dbbacSRobert Mustacchi 		    "temporary file for %s", fname);
13337e3dbbacSRobert Mustacchi 	}
13347e3dbbacSRobert Mustacchi 
13357e3dbbacSRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
1336d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
13377e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
13387e3dbbacSRobert Mustacchi 	}
13397e3dbbacSRobert Mustacchi 
13407e3dbbacSRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
13417e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
13427e3dbbacSRobert Mustacchi 		    tmpname);
13437e3dbbacSRobert Mustacchi 	}
13447e3dbbacSRobert Mustacchi 
13457e3dbbacSRobert Mustacchi 	free(tmpname);
13467e3dbbacSRobert Mustacchi }
13477e3dbbacSRobert Mustacchi 
13487e3dbbacSRobert Mustacchi /*
13497e3dbbacSRobert Mustacchi  * Look at a rule to determine whether or not we should consider including it or
13507e3dbbacSRobert Mustacchi  * not. At this point we've already filtered things such that we only get core
13517e3dbbacSRobert Mustacchi  * events.
13527e3dbbacSRobert Mustacchi  *
13537e3dbbacSRobert Mustacchi  * To consider an entry, we currently apply the following criteria:
13547e3dbbacSRobert Mustacchi  *
13557e3dbbacSRobert Mustacchi  * - The MSRIndex and MSRValue are zero. Programming additional MSRs is no
13567e3dbbacSRobert Mustacchi  *   supported right now.
13577e3dbbacSRobert Mustacchi  * - TakenAlone is non-zero, which means that it cannot run at the same time as
13587e3dbbacSRobert Mustacchi  *   another field.
13597e3dbbacSRobert Mustacchi  * - Offcore is one, indicating that it is off the core and we need to figure
13607e3dbbacSRobert Mustacchi  *   out if we can support this.
1361*43449cdcSRobert Mustacchi  * - If the counter is fixed, don't use it for now. "32"-"35" is another name
1362*43449cdcSRobert Mustacchi  *    for the fixed counters.
13637e3dbbacSRobert Mustacchi  * - If more than one value is specified in the EventCode or UMask values
13647e3dbbacSRobert Mustacchi  */
13657e3dbbacSRobert Mustacchi static boolean_t
1366d0e58ef5SRobert Mustacchi cpcgen_skip_intel_entry(nvlist_t *nvl, const char *path, uint_t ent)
13677e3dbbacSRobert Mustacchi {
13687e3dbbacSRobert Mustacchi 	char *event, *msridx, *msrval, *taken, *offcore, *counter;
13697e3dbbacSRobert Mustacchi 	char *ecode, *umask;
13707e3dbbacSRobert Mustacchi 
13717e3dbbacSRobert Mustacchi 	/*
13727e3dbbacSRobert Mustacchi 	 * Require EventName, it's kind of useless without that.
13737e3dbbacSRobert Mustacchi 	 */
13747e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "EventName", &event) != 0) {
13757e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "Found event without 'EventName' property "
13767e3dbbacSRobert Mustacchi 		    "in %s, entry %u", path, ent);
13777e3dbbacSRobert Mustacchi 	}
13787e3dbbacSRobert Mustacchi 
13797e3dbbacSRobert Mustacchi 	/*
13807e3dbbacSRobert Mustacchi 	 * If we can't find an expected value, whine about it.
13817e3dbbacSRobert Mustacchi 	 */
13827e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "MSRIndex", &msridx) != 0 ||
13837e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "MSRValue", &msrval) != 0 ||
13847e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Counter", &counter) != 0 ||
13857e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "EventCode", &ecode) != 0 ||
13867e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "UMask", &umask) != 0 ||
13877e3dbbacSRobert Mustacchi 	    nvlist_lookup_string(nvl, "Offcore", &offcore) != 0) {
13887e3dbbacSRobert Mustacchi 		warnx("Skipping event %s (index %u) from %s, missing required "
13897e3dbbacSRobert Mustacchi 		    "property", event, ent, path);
13907e3dbbacSRobert Mustacchi 		return (B_TRUE);
13917e3dbbacSRobert Mustacchi 	}
13927e3dbbacSRobert Mustacchi 
13937e3dbbacSRobert Mustacchi 	/*
13947e3dbbacSRobert Mustacchi 	 * MSRIndex and MSRvalue comes as either "0" or "0x00".
13957e3dbbacSRobert Mustacchi 	 */
13967e3dbbacSRobert Mustacchi 	if ((strcmp(msridx, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
13977e3dbbacSRobert Mustacchi 	    (strcmp(msrval, "0") != 0 && strcmp(msridx, "0x00") != 0) ||
13987e3dbbacSRobert Mustacchi 	    strcmp(offcore, "0") != 0 || strchr(ecode, ',') != NULL ||
13997e3dbbacSRobert Mustacchi 	    strchr(umask, ',') != NULL) {
14007e3dbbacSRobert Mustacchi 		return (B_TRUE);
14017e3dbbacSRobert Mustacchi 	}
14027e3dbbacSRobert Mustacchi 
14037e3dbbacSRobert Mustacchi 	/*
14047e3dbbacSRobert Mustacchi 	 * Unfortunately, not everything actually has "TakenAlone". If it
14057e3dbbacSRobert Mustacchi 	 * doesn't, we assume that it doesn't have to be.
14067e3dbbacSRobert Mustacchi 	 */
14077e3dbbacSRobert Mustacchi 	if (nvlist_lookup_string(nvl, "TakenAlone", &taken) == 0 &&
14087e3dbbacSRobert Mustacchi 	    strcmp(taken, "0") != 0) {
14097e3dbbacSRobert Mustacchi 		return (B_TRUE);
14107e3dbbacSRobert Mustacchi 	}
14117e3dbbacSRobert Mustacchi 
14127e3dbbacSRobert Mustacchi 
14137e3dbbacSRobert Mustacchi 	if (strncasecmp(counter, "fixed", strlen("fixed")) == 0)
14147e3dbbacSRobert Mustacchi 		return (B_TRUE);
1415*43449cdcSRobert Mustacchi 	if (strcmp(counter, "32") == 0 || strcmp(counter, "33") == 0 ||
1416*43449cdcSRobert Mustacchi 	    strcmp(counter, "34") == 0 || strcmp(counter, "35") == 0)
1417*43449cdcSRobert Mustacchi 		return (B_TRUE);
14187e3dbbacSRobert Mustacchi 
14197e3dbbacSRobert Mustacchi 	return (B_FALSE);
14207e3dbbacSRobert Mustacchi }
1421d0e58ef5SRobert Mustacchi static char *
1422d0e58ef5SRobert Mustacchi cpcgen_manual_amd_name(cpc_map_t *map)
1423d0e58ef5SRobert Mustacchi {
1424d0e58ef5SRobert Mustacchi 	char *name;
1425d0e58ef5SRobert Mustacchi 
1426d0e58ef5SRobert Mustacchi 	if (asprintf(&name, "amd_%s_events.3cpc", map->cmap_name) == -1) {
1427d0e58ef5SRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
1428d0e58ef5SRobert Mustacchi 		return (NULL);
1429d0e58ef5SRobert Mustacchi 	}
1430d0e58ef5SRobert Mustacchi 
1431d0e58ef5SRobert Mustacchi 	return (name);
1432d0e58ef5SRobert Mustacchi }
1433d0e58ef5SRobert Mustacchi 
1434d0e58ef5SRobert Mustacchi static boolean_t
1435d0e58ef5SRobert Mustacchi cpcgen_manual_amd_file_before(FILE *f, cpc_map_t *map)
1436d0e58ef5SRobert Mustacchi {
1437d0e58ef5SRobert Mustacchi 	size_t i;
143831aa6202SRobert Mustacchi 	char *upper, *desc, *c;
1439d0e58ef5SRobert Mustacchi 
1440d0e58ef5SRobert Mustacchi 	if ((upper = strdup(map->cmap_name)) == NULL) {
1441d0e58ef5SRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
1442d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1443d0e58ef5SRobert Mustacchi 	}
1444d0e58ef5SRobert Mustacchi 
144531aa6202SRobert Mustacchi 	if ((desc = strdup(map->cmap_name)) == NULL) {
144631aa6202SRobert Mustacchi 		warn("failed to duplicate manual name for %s", map->cmap_name);
144731aa6202SRobert Mustacchi 		free(upper);
144831aa6202SRobert Mustacchi 		return (B_FALSE);
144931aa6202SRobert Mustacchi 	}
145031aa6202SRobert Mustacchi 
1451d0e58ef5SRobert Mustacchi 	for (i = 0; upper[i] != '\0'; i++) {
1452d0e58ef5SRobert Mustacchi 		upper[i] = toupper(upper[i]);
1453d0e58ef5SRobert Mustacchi 	}
1454d0e58ef5SRobert Mustacchi 
145531aa6202SRobert Mustacchi 	desc++;
145631aa6202SRobert Mustacchi 	c = strchr(desc, '_');
145731aa6202SRobert Mustacchi 	if (c != NULL) {
145831aa6202SRobert Mustacchi 		*c = ' ';
145931aa6202SRobert Mustacchi 		c++;
146031aa6202SRobert Mustacchi 		*c = toupper(*c);
146131aa6202SRobert Mustacchi 	}
1462d0e58ef5SRobert Mustacchi 
1463d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_amd_header, map->cmap_path, upper,
146431aa6202SRobert Mustacchi 	    map->cmap_name, desc, desc) == -1) {
1465d0e58ef5SRobert Mustacchi 		warn("failed to write out manual header for %s",
1466d0e58ef5SRobert Mustacchi 		    map->cmap_name);
1467d0e58ef5SRobert Mustacchi 		free(upper);
146831aa6202SRobert Mustacchi 		free(desc);
1469d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1470d0e58ef5SRobert Mustacchi 	}
1471d0e58ef5SRobert Mustacchi 
1472d0e58ef5SRobert Mustacchi 	free(upper);
147331aa6202SRobert Mustacchi 	free(desc);
1474d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1475d0e58ef5SRobert Mustacchi }
1476d0e58ef5SRobert Mustacchi 
1477d0e58ef5SRobert Mustacchi static boolean_t
1478d0e58ef5SRobert Mustacchi cpcgen_manual_amd_file_after(FILE *f, cpc_map_t *map)
1479d0e58ef5SRobert Mustacchi {
1480d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_manual_amd_trailer) == -1) {
1481d0e58ef5SRobert Mustacchi 		warn("failed to write out manual header for %s",
1482d0e58ef5SRobert Mustacchi 		    map->cmap_name);
1483d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1484d0e58ef5SRobert Mustacchi 	}
1485d0e58ef5SRobert Mustacchi 
1486d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1487d0e58ef5SRobert Mustacchi }
1488d0e58ef5SRobert Mustacchi 
1489d0e58ef5SRobert Mustacchi static boolean_t
1490d0e58ef5SRobert Mustacchi cpcgen_manual_amd_event(FILE *f, nvlist_t *nvl, const char *path, uint32_t ent)
1491d0e58ef5SRobert Mustacchi {
1492d0e58ef5SRobert Mustacchi 	char *name, *mnemonic = NULL, *summary = NULL, *desc = NULL;
1493d0e58ef5SRobert Mustacchi 	char *umode;
1494d0e58ef5SRobert Mustacchi 	nvlist_t *units = NULL;
1495d0e58ef5SRobert Mustacchi 	uint32_t i, length;
1496d0e58ef5SRobert Mustacchi 
1497d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "name", &name) != 0) {
1498d0e58ef5SRobert Mustacchi 		warnx("Found event without 'name' property in %s, entry %u",
1499d0e58ef5SRobert Mustacchi 		    path, ent);
1500d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1501d0e58ef5SRobert Mustacchi 	}
1502d0e58ef5SRobert Mustacchi 
1503d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "mnemonic", &mnemonic) != 0 ||
1504d0e58ef5SRobert Mustacchi 	    nvlist_lookup_string(nvl, "summary", &summary) != 0) {
1505d0e58ef5SRobert Mustacchi 		warnx("event %s in %s, entry %u, missing required fields",
1506d0e58ef5SRobert Mustacchi 		    name, path, ent);
1507d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1508d0e58ef5SRobert Mustacchi 	}
1509d0e58ef5SRobert Mustacchi 
1510d0e58ef5SRobert Mustacchi 	/*
1511d0e58ef5SRobert Mustacchi 	 * Allow the other fields to be missing.
1512d0e58ef5SRobert Mustacchi 	 */
1513d0e58ef5SRobert Mustacchi 	(void) nvlist_lookup_string(nvl, "description", &desc);
1514d0e58ef5SRobert Mustacchi 	(void) nvlist_lookup_nvlist(nvl, "units", &units);
1515d0e58ef5SRobert Mustacchi 
1516d0e58ef5SRobert Mustacchi 	if (fprintf(f, ".It Sy %s\n", name) == -1) {
1517d0e58ef5SRobert Mustacchi 		warn("failed to write out event entry %s", name);
1518d0e58ef5SRobert Mustacchi 	}
1519d0e58ef5SRobert Mustacchi 
1520d0e58ef5SRobert Mustacchi 	if (fprintf(f, ".Sy %s -\n"
1521d0e58ef5SRobert Mustacchi 	    "%s\n", mnemonic, summary) == -1) {
1522d0e58ef5SRobert Mustacchi 		warn("failed to write out event entry %s", name);
1523d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1524d0e58ef5SRobert Mustacchi 	}
1525d0e58ef5SRobert Mustacchi 
1526d0e58ef5SRobert Mustacchi 	if (desc != NULL) {
1527d0e58ef5SRobert Mustacchi 		if (fprintf(f, ".Pp\n%s\n", desc) == -1) {
1528d0e58ef5SRobert Mustacchi 			warn("failed to write out event entry %s", name);
1529d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1530d0e58ef5SRobert Mustacchi 		}
1531d0e58ef5SRobert Mustacchi 	}
1532d0e58ef5SRobert Mustacchi 
1533d0e58ef5SRobert Mustacchi 	if (units == NULL)
1534d0e58ef5SRobert Mustacchi 		return (B_TRUE);
1535d0e58ef5SRobert Mustacchi 
1536d0e58ef5SRobert Mustacchi 	/*
1537d0e58ef5SRobert Mustacchi 	 * Skip units we don't know how to handle.
1538d0e58ef5SRobert Mustacchi 	 */
1539d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "unit_mode", &umode) == 0) {
1540d0e58ef5SRobert Mustacchi 		return (B_TRUE);
1541d0e58ef5SRobert Mustacchi 	}
1542d0e58ef5SRobert Mustacchi 
1543d0e58ef5SRobert Mustacchi 	if (fprintf(f, ".Pp\n"
1544d0e58ef5SRobert Mustacchi 	    "This event has the following units which may be used\n"
1545d0e58ef5SRobert Mustacchi 	    "to modify the behavior of the event:\n"
1546d0e58ef5SRobert Mustacchi 	    ".Bl -tag -width Sy\n") == -1) {
1547d0e58ef5SRobert Mustacchi 		warn("failed to write out event entry %s", name);
1548d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1549d0e58ef5SRobert Mustacchi 	}
1550d0e58ef5SRobert Mustacchi 
1551d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_uint32(units, "length", &length) != 0) {
1552d0e58ef5SRobert Mustacchi 		warnx("found units array, but could not look up length "
1553d0e58ef5SRobert Mustacchi 		    "property for events %s (index %u) in file %s",
1554d0e58ef5SRobert Mustacchi 		    name, ent, path);
1555d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1556d0e58ef5SRobert Mustacchi 	}
1557d0e58ef5SRobert Mustacchi 
1558d0e58ef5SRobert Mustacchi 	for (i = 0; i < length; i++) {
1559d0e58ef5SRobert Mustacchi 		nvlist_t *uvl;
1560d0e58ef5SRobert Mustacchi 		char num[64];
1561d0e58ef5SRobert Mustacchi 		char *uname, *udesc = NULL;
1562d0e58ef5SRobert Mustacchi 
1563d0e58ef5SRobert Mustacchi 		(void) snprintf(num, sizeof (num), "%u", i);
1564d0e58ef5SRobert Mustacchi 		if (nvlist_lookup_nvlist(units, num, &uvl) != 0) {
1565d0e58ef5SRobert Mustacchi 			warnx("failed to look up unit %u for event %s (index "
1566d0e58ef5SRobert Mustacchi 			    "%u) in file %s", i, name, ent, path);
1567d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1568d0e58ef5SRobert Mustacchi 		}
1569d0e58ef5SRobert Mustacchi 
1570d0e58ef5SRobert Mustacchi 		if (nvlist_lookup_string(uvl, "name", &uname) != 0) {
1571d0e58ef5SRobert Mustacchi 			warnx("failed to find required members for unit array "
1572d0e58ef5SRobert Mustacchi 			    "entry %u of event %s (index %u) from file %s",
1573d0e58ef5SRobert Mustacchi 			    i, name, ent, path);
1574d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1575d0e58ef5SRobert Mustacchi 		}
1576d0e58ef5SRobert Mustacchi 		(void) nvlist_lookup_string(uvl, "description", &udesc);
1577d0e58ef5SRobert Mustacchi 		if (fprintf(f, ".It Sy %s\n", uname) == -1) {
1578d0e58ef5SRobert Mustacchi 			warn("failed to write out event entry %s", name);
1579d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1580d0e58ef5SRobert Mustacchi 		}
1581d0e58ef5SRobert Mustacchi 
1582d0e58ef5SRobert Mustacchi 		if (udesc != NULL) {
1583d0e58ef5SRobert Mustacchi 			if (fprintf(f, "%s\n", udesc) == -1) {
1584d0e58ef5SRobert Mustacchi 				warn("failed to write out event entry %s",
1585d0e58ef5SRobert Mustacchi 				    name);
1586d0e58ef5SRobert Mustacchi 				return (B_FALSE);
1587d0e58ef5SRobert Mustacchi 			}
1588d0e58ef5SRobert Mustacchi 		}
1589d0e58ef5SRobert Mustacchi 	}
1590d0e58ef5SRobert Mustacchi 
1591d0e58ef5SRobert Mustacchi 	if (fprintf(f, ".El\n") == -1) {
1592d0e58ef5SRobert Mustacchi 		warn("failed to write out event entry %s",
1593d0e58ef5SRobert Mustacchi 		    name);
1594d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1595d0e58ef5SRobert Mustacchi 	}
1596d0e58ef5SRobert Mustacchi 
1597d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1598d0e58ef5SRobert Mustacchi }
1599d0e58ef5SRobert Mustacchi 
1600d0e58ef5SRobert Mustacchi static char *
1601d0e58ef5SRobert Mustacchi cpcgen_cfile_amd_name(cpc_map_t *map)
1602d0e58ef5SRobert Mustacchi {
1603d0e58ef5SRobert Mustacchi 	char *name;
1604d0e58ef5SRobert Mustacchi 
1605d0e58ef5SRobert Mustacchi 	if (asprintf(&name, "opteron_pcbe_%s.c", map->cmap_name) == -1) {
1606d0e58ef5SRobert Mustacchi 		warn("failed to assemble file name for %s", map->cmap_path);
1607d0e58ef5SRobert Mustacchi 		return (NULL);
1608d0e58ef5SRobert Mustacchi 	}
1609d0e58ef5SRobert Mustacchi 
1610d0e58ef5SRobert Mustacchi 	return (name);
1611d0e58ef5SRobert Mustacchi }
1612d0e58ef5SRobert Mustacchi 
1613d0e58ef5SRobert Mustacchi /*
1614d0e58ef5SRobert Mustacchi  * Generate a header file that can be used to synthesize the data events we care
1615d0e58ef5SRobert Mustacchi  * about.
1616d0e58ef5SRobert Mustacchi  */
1617d0e58ef5SRobert Mustacchi static void
1618d0e58ef5SRobert Mustacchi cpcgen_common_amd_files(int dirfd)
1619d0e58ef5SRobert Mustacchi {
1620d0e58ef5SRobert Mustacchi 	const char *fname = "opteron_pcbe_cpcgen.h";
1621d0e58ef5SRobert Mustacchi 	char *tmpname;
1622d0e58ef5SRobert Mustacchi 	int fd;
1623d0e58ef5SRobert Mustacchi 	FILE *f;
1624d0e58ef5SRobert Mustacchi 	cpc_map_t *map;
1625d0e58ef5SRobert Mustacchi 
1626d0e58ef5SRobert Mustacchi 	if (asprintf(&tmpname, ".%s.%d", fname, getpid()) == -1) {
1627d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to construct temporary file name");
1628d0e58ef5SRobert Mustacchi 	}
1629d0e58ef5SRobert Mustacchi 
1630d0e58ef5SRobert Mustacchi 	if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0644)) < 0) {
1631d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to create temporary file %s",
1632d0e58ef5SRobert Mustacchi 		    tmpname);
1633d0e58ef5SRobert Mustacchi 	}
1634d0e58ef5SRobert Mustacchi 
1635d0e58ef5SRobert Mustacchi 	if ((f = fdopen(fd, "w")) == NULL) {
1636d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
1637d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to fdopen temporary file");
1638d0e58ef5SRobert Mustacchi 	}
1639d0e58ef5SRobert Mustacchi 
1640d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_cddl_header) == -1) {
1641d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
1642d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to write header to "
1643d0e58ef5SRobert Mustacchi 		    "temporary file for %s", fname);
1644d0e58ef5SRobert Mustacchi 	}
1645d0e58ef5SRobert Mustacchi 
1646d0e58ef5SRobert Mustacchi 	if (fprintf(f, "#ifndef _OPTERON_PCBE_CPCGEN_H\n"
1647d0e58ef5SRobert Mustacchi 	    "#define\t_OPTERON_PCBE_CPCGEN_H\n"
1648d0e58ef5SRobert Mustacchi 	    "\n"
1649d0e58ef5SRobert Mustacchi 	    "#ifdef __cplusplus\n"
1650d0e58ef5SRobert Mustacchi 	    "extern \"C\" {\n"
1651d0e58ef5SRobert Mustacchi 	    "#endif\n"
1652d0e58ef5SRobert Mustacchi 	    "\n") == -1) {
1653d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
1654d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to write header to "
1655d0e58ef5SRobert Mustacchi 		    "temporary file for %s", fname);
1656d0e58ef5SRobert Mustacchi 	}
1657d0e58ef5SRobert Mustacchi 
1658d0e58ef5SRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
1659d0e58ef5SRobert Mustacchi 		if (fprintf(f, "extern const amd_event_t "
1660d0e58ef5SRobert Mustacchi 		    "opteron_pcbe_%s_events[];\n", map->cmap_name) == -1) {
1661d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
1662d0e58ef5SRobert Mustacchi 			err(EXIT_FAILURE, "failed to write header to "
1663d0e58ef5SRobert Mustacchi 			    "temporary file for %s", fname);
1664d0e58ef5SRobert Mustacchi 		}
1665d0e58ef5SRobert Mustacchi 	}
1666d0e58ef5SRobert Mustacchi 
1667d0e58ef5SRobert Mustacchi 	if (fprintf(f, "\n"
1668d0e58ef5SRobert Mustacchi 	    "#ifdef __cplusplus\n"
1669d0e58ef5SRobert Mustacchi 	    "}\n"
1670d0e58ef5SRobert Mustacchi 	    "#endif\n"
1671d0e58ef5SRobert Mustacchi 	    "\n"
1672d0e58ef5SRobert Mustacchi 	    "#endif /* _OPTERON_PCBE_CPCGEN_H */\n") == -1) {
1673d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
1674d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to write header to "
1675d0e58ef5SRobert Mustacchi 		    "temporary file for %s", fname);
1676d0e58ef5SRobert Mustacchi 	}
1677d0e58ef5SRobert Mustacchi 
1678d0e58ef5SRobert Mustacchi 
1679d0e58ef5SRobert Mustacchi 
1680d0e58ef5SRobert Mustacchi 	if (fflush(f) != 0 || fclose(f) != 0) {
1681d0e58ef5SRobert Mustacchi 		cpcgen_remove_tmpfile(dirfd, tmpname);
1682d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to flush and close temporary file");
1683d0e58ef5SRobert Mustacchi 	}
1684d0e58ef5SRobert Mustacchi 
1685d0e58ef5SRobert Mustacchi 	if (renameat(dirfd, tmpname, dirfd, fname) != 0) {
1686d0e58ef5SRobert Mustacchi 		err(EXIT_FAILURE, "failed to rename temporary file %s",
1687d0e58ef5SRobert Mustacchi 		    tmpname);
1688d0e58ef5SRobert Mustacchi 	}
1689d0e58ef5SRobert Mustacchi 
1690d0e58ef5SRobert Mustacchi 	free(tmpname);
1691d0e58ef5SRobert Mustacchi }
1692d0e58ef5SRobert Mustacchi 
1693d0e58ef5SRobert Mustacchi static boolean_t
1694d0e58ef5SRobert Mustacchi cpcgen_cfile_amd_before(FILE *f, cpc_map_t *map)
1695d0e58ef5SRobert Mustacchi {
1696d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_amd_header, map->cmap_name) == -1) {
1697d0e58ef5SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
1698d0e58ef5SRobert Mustacchi 		    map->cmap_path);
1699d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1700d0e58ef5SRobert Mustacchi 	}
1701d0e58ef5SRobert Mustacchi 
1702d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_amd_table_start, map->cmap_name) == -1) {
1703d0e58ef5SRobert Mustacchi 		warn("failed to write header to temporary file for %s",
1704d0e58ef5SRobert Mustacchi 		    map->cmap_path);
1705d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1706d0e58ef5SRobert Mustacchi 	}
1707d0e58ef5SRobert Mustacchi 
1708d0e58ef5SRobert Mustacchi 
1709d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1710d0e58ef5SRobert Mustacchi }
1711d0e58ef5SRobert Mustacchi 
1712d0e58ef5SRobert Mustacchi static boolean_t
1713d0e58ef5SRobert Mustacchi cpcgen_cfile_amd_after(FILE *f, cpc_map_t *map)
1714d0e58ef5SRobert Mustacchi {
1715d0e58ef5SRobert Mustacchi 	if (fprintf(f, cpcgen_cfile_amd_table_end) == -1) {
1716d0e58ef5SRobert Mustacchi 		warn("failed to write footer to temporary file for %s",
1717d0e58ef5SRobert Mustacchi 		    map->cmap_path);
1718d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1719d0e58ef5SRobert Mustacchi 	}
1720d0e58ef5SRobert Mustacchi 
1721d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1722d0e58ef5SRobert Mustacchi }
1723d0e58ef5SRobert Mustacchi 
1724d0e58ef5SRobert Mustacchi static boolean_t
1725d0e58ef5SRobert Mustacchi cpcgen_cfile_amd_event(FILE *f, nvlist_t *nvl, const char *path, uint_t ent)
1726d0e58ef5SRobert Mustacchi {
1727d0e58ef5SRobert Mustacchi 	char *name, *code, *umode;
1728d0e58ef5SRobert Mustacchi 	uint32_t i, length;
1729d0e58ef5SRobert Mustacchi 	nvlist_t *units;
1730d0e58ef5SRobert Mustacchi 
1731d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "name", &name) != 0) {
1732d0e58ef5SRobert Mustacchi 		warnx("Found event without 'name' property in %s, entry %u",
1733d0e58ef5SRobert Mustacchi 		    path, ent);
1734d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1735d0e58ef5SRobert Mustacchi 	}
1736d0e58ef5SRobert Mustacchi 
1737d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "code", &code) != 0) {
1738d0e58ef5SRobert Mustacchi 		warnx("event %s (index %u) from %s missing required properties "
1739d0e58ef5SRobert Mustacchi 		    "for C translation", name, path, ent);
1740d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1741d0e58ef5SRobert Mustacchi 	}
1742d0e58ef5SRobert Mustacchi 
1743d0e58ef5SRobert Mustacchi 	if (fprintf(f, "\t{ \"%s\", %s, 0 },\n", name, code) == -1) {
1744d0e58ef5SRobert Mustacchi 		warn("failed to write out entry %s from %s", name, path);
1745d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1746d0e58ef5SRobert Mustacchi 	}
1747d0e58ef5SRobert Mustacchi 
1748d0e58ef5SRobert Mustacchi 	/*
1749d0e58ef5SRobert Mustacchi 	 * The 'units' array is optional. If the rule has a specific 'unit_mode'
1750d0e58ef5SRobert Mustacchi 	 * indicating how the units should be combined, skip that. We don't know
1751d0e58ef5SRobert Mustacchi 	 * how to properly process that right now.
1752d0e58ef5SRobert Mustacchi 	 */
1753d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_nvlist(nvl, "units", &units) != 0) {
1754d0e58ef5SRobert Mustacchi 		return (B_TRUE);
1755d0e58ef5SRobert Mustacchi 	}
1756d0e58ef5SRobert Mustacchi 
1757d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_string(nvl, "unit_mode", &umode) == 0) {
1758d0e58ef5SRobert Mustacchi 		return (B_TRUE);
1759d0e58ef5SRobert Mustacchi 	}
1760d0e58ef5SRobert Mustacchi 
1761d0e58ef5SRobert Mustacchi 	if (nvlist_lookup_uint32(units, "length", &length) != 0) {
1762d0e58ef5SRobert Mustacchi 		warnx("found units array, but could not look up length "
1763d0e58ef5SRobert Mustacchi 		    "property for events %s (index %u) in file %s",
1764d0e58ef5SRobert Mustacchi 		    name, ent, path);
1765d0e58ef5SRobert Mustacchi 		return (B_FALSE);
1766d0e58ef5SRobert Mustacchi 	}
1767d0e58ef5SRobert Mustacchi 
1768d0e58ef5SRobert Mustacchi 	for (i = 0; i < length; i++) {
1769d0e58ef5SRobert Mustacchi 		nvlist_t *uvl;
1770d0e58ef5SRobert Mustacchi 		char num[64];
1771d0e58ef5SRobert Mustacchi 		char *uname, *urw;
1772d0e58ef5SRobert Mustacchi 		int32_t bit;
1773d0e58ef5SRobert Mustacchi 
1774d0e58ef5SRobert Mustacchi 		(void) snprintf(num, sizeof (num), "%u", i);
1775d0e58ef5SRobert Mustacchi 		if (nvlist_lookup_nvlist(units, num, &uvl) != 0) {
1776d0e58ef5SRobert Mustacchi 			warnx("failed to look up unit %u for event %s (index "
1777d0e58ef5SRobert Mustacchi 			    "%u) in file %s", i, name, ent, path);
1778d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1779d0e58ef5SRobert Mustacchi 		}
1780d0e58ef5SRobert Mustacchi 
1781d0e58ef5SRobert Mustacchi 		if (nvlist_lookup_string(uvl, "name", &uname) != 0 ||
1782d0e58ef5SRobert Mustacchi 		    nvlist_lookup_string(uvl, "rw", &urw) != 0 ||
1783d0e58ef5SRobert Mustacchi 		    nvlist_lookup_int32(uvl, "bit", &bit) != 0) {
1784d0e58ef5SRobert Mustacchi 			warnx("failed to find required members for unit array "
1785d0e58ef5SRobert Mustacchi 			    "entry %u of event %s (index %u) from file %s",
1786d0e58ef5SRobert Mustacchi 			    i, name, ent, path);
1787d0e58ef5SRobert Mustacchi 			dump_nvlist(uvl, 0);
1788d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1789d0e58ef5SRobert Mustacchi 		}
1790d0e58ef5SRobert Mustacchi 
1791d0e58ef5SRobert Mustacchi 		if (bit < 0 || bit > 31) {
1792d0e58ef5SRobert Mustacchi 			warnx("event %s (index %u) from file %s has invalid "
1793d0e58ef5SRobert Mustacchi 			    "bit value: %d; skipping", name, ent, path, bit);
1794d0e58ef5SRobert Mustacchi 			continue;
1795d0e58ef5SRobert Mustacchi 		}
1796d0e58ef5SRobert Mustacchi 
1797d0e58ef5SRobert Mustacchi 		if (strcasecmp(urw, "Read-write") != 0)
1798d0e58ef5SRobert Mustacchi 			continue;
1799d0e58ef5SRobert Mustacchi 
1800d0e58ef5SRobert Mustacchi 		if (fprintf(f, "\t{ \"%s.%s\", %s, 0x%x },\n", name, uname,
1801d0e58ef5SRobert Mustacchi 		    code, 1U << bit) == -1) {
1802d0e58ef5SRobert Mustacchi 			warn("failed to write out entry %s from %s", name,
1803d0e58ef5SRobert Mustacchi 			    path);
1804d0e58ef5SRobert Mustacchi 			return (B_FALSE);
1805d0e58ef5SRobert Mustacchi 		}
1806d0e58ef5SRobert Mustacchi 	}
1807d0e58ef5SRobert Mustacchi 
1808d0e58ef5SRobert Mustacchi 	return (B_TRUE);
1809d0e58ef5SRobert Mustacchi }
18107e3dbbacSRobert Mustacchi 
18117e3dbbacSRobert Mustacchi /*
18127e3dbbacSRobert Mustacchi  * For each processor family, generate a data file that contains all of the
18137e3dbbacSRobert Mustacchi  * events that we support. Also generate a header that can be included that
18147e3dbbacSRobert Mustacchi  * declares all of the tables.
18157e3dbbacSRobert Mustacchi  */
18167e3dbbacSRobert Mustacchi static void
18177e3dbbacSRobert Mustacchi cpcgen_gen(int dirfd)
18187e3dbbacSRobert Mustacchi {
18197e3dbbacSRobert Mustacchi 	cpc_map_t *map = cpcgen_maps;
18207e3dbbacSRobert Mustacchi 
18217e3dbbacSRobert Mustacchi 	if (map == NULL) {
18227e3dbbacSRobert Mustacchi 		errx(EXIT_FAILURE, "no platforms found or matched");
18237e3dbbacSRobert Mustacchi 	}
18247e3dbbacSRobert Mustacchi 
18257e3dbbacSRobert Mustacchi 	for (map = cpcgen_maps; map != NULL; map = map->cmap_next) {
18267e3dbbacSRobert Mustacchi 		int fd, ret;
18277e3dbbacSRobert Mustacchi 		FILE *f;
18287e3dbbacSRobert Mustacchi 		char *tmpname, *name;
18297e3dbbacSRobert Mustacchi 		uint32_t length, i;
18307e3dbbacSRobert Mustacchi 
18317e3dbbacSRobert Mustacchi 		if ((name = cpcgen_ops.cgen_op_name(map)) == NULL) {
18327e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
18337e3dbbacSRobert Mustacchi 		}
18347e3dbbacSRobert Mustacchi 
18357e3dbbacSRobert Mustacchi 		if (asprintf(&tmpname, ".%s.%d", name, getpid()) == -1) {
18367e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to construct temporary file "
18377e3dbbacSRobert Mustacchi 			    "name");
18387e3dbbacSRobert Mustacchi 		}
18397e3dbbacSRobert Mustacchi 
18407e3dbbacSRobert Mustacchi 		if ((fd = openat(dirfd, tmpname, O_RDWR | O_CREAT, 0444)) < 0) {
18417e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to create temporary file %s",
18427e3dbbacSRobert Mustacchi 			    tmpname);
18437e3dbbacSRobert Mustacchi 		}
18447e3dbbacSRobert Mustacchi 
18457e3dbbacSRobert Mustacchi 		if ((f = fdopen(fd, "w")) == NULL) {
1846d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
18477e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to fdopen temporary file");
18487e3dbbacSRobert Mustacchi 		}
18497e3dbbacSRobert Mustacchi 
18507e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_before(f, map)) {
1851d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
18527e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
18537e3dbbacSRobert Mustacchi 		}
18547e3dbbacSRobert Mustacchi 
18557e3dbbacSRobert Mustacchi 		/*
18567e3dbbacSRobert Mustacchi 		 * Iterate over array contents.
18577e3dbbacSRobert Mustacchi 		 */
18587e3dbbacSRobert Mustacchi 		if ((ret = nvlist_lookup_uint32(map->cmap_data, "length",
18597e3dbbacSRobert Mustacchi 		    &length)) != 0) {
18607e3dbbacSRobert Mustacchi 			errx(EXIT_FAILURE, "failed to look up length property "
18617e3dbbacSRobert Mustacchi 			    "in parsed data for %s: %s", map->cmap_path,
18627e3dbbacSRobert Mustacchi 			    strerror(ret));
18637e3dbbacSRobert Mustacchi 		}
18647e3dbbacSRobert Mustacchi 
18657e3dbbacSRobert Mustacchi 		for (i = 0; i < length; i++) {
18667e3dbbacSRobert Mustacchi 			nvlist_t *nvl;
18677e3dbbacSRobert Mustacchi 			char num[64];
18687e3dbbacSRobert Mustacchi 
18697e3dbbacSRobert Mustacchi 			(void) snprintf(num, sizeof (num), "%u", i);
18707e3dbbacSRobert Mustacchi 			if ((ret = nvlist_lookup_nvlist(map->cmap_data,
18717e3dbbacSRobert Mustacchi 			    num, &nvl)) != 0) {
1872d0e58ef5SRobert Mustacchi 				cpcgen_remove_tmpfile(dirfd, tmpname);
18737e3dbbacSRobert Mustacchi 				errx(EXIT_FAILURE, "failed to look up array "
18747e3dbbacSRobert Mustacchi 				    "entry %u in parsed data for %s: %s", i,
18757e3dbbacSRobert Mustacchi 				    map->cmap_path, strerror(ret));
18767e3dbbacSRobert Mustacchi 			}
18777e3dbbacSRobert Mustacchi 
1878d0e58ef5SRobert Mustacchi 			if (cpcgen_ops.cgen_op_skip != NULL &&
1879d0e58ef5SRobert Mustacchi 			    cpcgen_ops.cgen_op_skip(nvl, map->cmap_path, i)) {
18807e3dbbacSRobert Mustacchi 				continue;
1881d0e58ef5SRobert Mustacchi 			}
18827e3dbbacSRobert Mustacchi 
18837e3dbbacSRobert Mustacchi 			if (!cpcgen_ops.cgen_op_event(f, nvl, map->cmap_path,
18847e3dbbacSRobert Mustacchi 			    i)) {
1885d0e58ef5SRobert Mustacchi 				cpcgen_remove_tmpfile(dirfd, tmpname);
18867e3dbbacSRobert Mustacchi 				exit(EXIT_FAILURE);
18877e3dbbacSRobert Mustacchi 			}
18887e3dbbacSRobert Mustacchi 		}
18897e3dbbacSRobert Mustacchi 
18907e3dbbacSRobert Mustacchi 		if (!cpcgen_ops.cgen_op_file_after(f, map)) {
1891d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
18927e3dbbacSRobert Mustacchi 			exit(EXIT_FAILURE);
18937e3dbbacSRobert Mustacchi 		}
18947e3dbbacSRobert Mustacchi 
18957e3dbbacSRobert Mustacchi 		if (fflush(f) != 0 || fclose(f) != 0) {
1896d0e58ef5SRobert Mustacchi 			cpcgen_remove_tmpfile(dirfd, tmpname);
18977e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to flush and close "
18987e3dbbacSRobert Mustacchi 			    "temporary file");
18997e3dbbacSRobert Mustacchi 		}
19007e3dbbacSRobert Mustacchi 
19017e3dbbacSRobert Mustacchi 		if (renameat(dirfd, tmpname, dirfd, name) != 0) {
19027e3dbbacSRobert Mustacchi 			err(EXIT_FAILURE, "failed to rename temporary file %s",
19037e3dbbacSRobert Mustacchi 			    tmpname);
19047e3dbbacSRobert Mustacchi 		}
19057e3dbbacSRobert Mustacchi 
19067e3dbbacSRobert Mustacchi 		free(name);
19077e3dbbacSRobert Mustacchi 		free(tmpname);
19087e3dbbacSRobert Mustacchi 	}
19097e3dbbacSRobert Mustacchi }
19107e3dbbacSRobert Mustacchi 
19117e3dbbacSRobert Mustacchi static void
19127e3dbbacSRobert Mustacchi cpcgen_usage(const char *fmt, ...)
19137e3dbbacSRobert Mustacchi {
19147e3dbbacSRobert Mustacchi 	if (fmt != NULL) {
19157e3dbbacSRobert Mustacchi 		va_list ap;
19167e3dbbacSRobert Mustacchi 
19177e3dbbacSRobert Mustacchi 		(void) fprintf(stderr, "%s: ", cpcgen_progname);
19187e3dbbacSRobert Mustacchi 		va_start(ap, fmt);
19197e3dbbacSRobert Mustacchi 		(void) vfprintf(stderr, fmt, ap);
19207e3dbbacSRobert Mustacchi 		va_end(ap);
19217e3dbbacSRobert Mustacchi 	}
19227e3dbbacSRobert Mustacchi 
19237e3dbbacSRobert Mustacchi 	(void) fprintf(stderr, "Usage: %s -a|-p platform -c|-H|-m -d datadir "
19247e3dbbacSRobert Mustacchi 	    "-o outdir\n"
19257e3dbbacSRobert Mustacchi 	    "\n"
19267e3dbbacSRobert Mustacchi 	    "\t-a  generate data for all platforms\n"
19277e3dbbacSRobert Mustacchi 	    "\t-c  generate C file for CPC\n"
19287e3dbbacSRobert Mustacchi 	    "\t-d  specify the directory containt perfmon data\n"
1929d0e58ef5SRobert Mustacchi 	    "\t-H  generate header file and common files\n"
19307e3dbbacSRobert Mustacchi 	    "\t-m  generate manual pages for CPC data\n"
1931d0e58ef5SRobert Mustacchi 	    "\t-o  output files in directory outdir\n"
19327e3dbbacSRobert Mustacchi 	    "\t-p  generate data for a specified platform\n",
19337e3dbbacSRobert Mustacchi 	    cpcgen_progname);
19347e3dbbacSRobert Mustacchi }
19357e3dbbacSRobert Mustacchi 
19367e3dbbacSRobert Mustacchi int
19377e3dbbacSRobert Mustacchi main(int argc, char *argv[])
19387e3dbbacSRobert Mustacchi {
19397e3dbbacSRobert Mustacchi 	int c, outdirfd;
19407e3dbbacSRobert Mustacchi 	boolean_t do_mpage = B_FALSE, do_cfile = B_FALSE, do_header = B_FALSE,
19417e3dbbacSRobert Mustacchi 	    do_all = B_FALSE;
19427e3dbbacSRobert Mustacchi 	const char *datadir = NULL, *outdir = NULL, *platform = NULL;
19437e3dbbacSRobert Mustacchi 	uint_t count = 0;
19447e3dbbacSRobert Mustacchi 
19457e3dbbacSRobert Mustacchi 	cpcgen_progname = basename(argv[0]);
19467e3dbbacSRobert Mustacchi 
19477e3dbbacSRobert Mustacchi 	while ((c = getopt(argc, argv, ":acd:hHmo:p:")) != -1) {
19487e3dbbacSRobert Mustacchi 		switch (c) {
19497e3dbbacSRobert Mustacchi 		case 'a':
19507e3dbbacSRobert Mustacchi 			do_all = B_TRUE;
19517e3dbbacSRobert Mustacchi 			break;
19527e3dbbacSRobert Mustacchi 		case 'c':
19537e3dbbacSRobert Mustacchi 			do_cfile = B_TRUE;
19547e3dbbacSRobert Mustacchi 			break;
19557e3dbbacSRobert Mustacchi 		case 'd':
19567e3dbbacSRobert Mustacchi 			datadir = optarg;
19577e3dbbacSRobert Mustacchi 			break;
19587e3dbbacSRobert Mustacchi 		case 'm':
19597e3dbbacSRobert Mustacchi 			do_mpage = B_TRUE;
19607e3dbbacSRobert Mustacchi 			break;
19617e3dbbacSRobert Mustacchi 		case 'H':
19627e3dbbacSRobert Mustacchi 			do_header = B_TRUE;
19637e3dbbacSRobert Mustacchi 			break;
19647e3dbbacSRobert Mustacchi 		case 'o':
19657e3dbbacSRobert Mustacchi 			outdir = optarg;
19667e3dbbacSRobert Mustacchi 			break;
19677e3dbbacSRobert Mustacchi 		case 'p':
19687e3dbbacSRobert Mustacchi 			platform = optarg;
19697e3dbbacSRobert Mustacchi 			break;
19707e3dbbacSRobert Mustacchi 		case ':':
19717e3dbbacSRobert Mustacchi 			cpcgen_usage("Option -%c requires an operand\n",
19727e3dbbacSRobert Mustacchi 			    optopt);
19737e3dbbacSRobert Mustacchi 			return (2);
19747e3dbbacSRobert Mustacchi 		case '?':
19757e3dbbacSRobert Mustacchi 			cpcgen_usage("Unknown option: -%c\n", optopt);
19767e3dbbacSRobert Mustacchi 			return (2);
19777e3dbbacSRobert Mustacchi 		case 'h':
19787e3dbbacSRobert Mustacchi 		default:
19797e3dbbacSRobert Mustacchi 			cpcgen_usage(NULL);
19807e3dbbacSRobert Mustacchi 			return (2);
19817e3dbbacSRobert Mustacchi 		}
19827e3dbbacSRobert Mustacchi 	}
19837e3dbbacSRobert Mustacchi 
19847e3dbbacSRobert Mustacchi 	count = 0;
19857e3dbbacSRobert Mustacchi 	if (do_mpage)
19867e3dbbacSRobert Mustacchi 		count++;
19877e3dbbacSRobert Mustacchi 	if (do_cfile)
19887e3dbbacSRobert Mustacchi 		count++;
19897e3dbbacSRobert Mustacchi 	if (do_header)
19907e3dbbacSRobert Mustacchi 		count++;
19917e3dbbacSRobert Mustacchi 	if (count > 1) {
19927e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -c, -h, and -m may be specified\n");
19937e3dbbacSRobert Mustacchi 		return (2);
19947e3dbbacSRobert Mustacchi 	} else if (count == 0) {
19957e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -c, -h, and -m is required\n");
19967e3dbbacSRobert Mustacchi 		return (2);
19977e3dbbacSRobert Mustacchi 	}
19987e3dbbacSRobert Mustacchi 
19997e3dbbacSRobert Mustacchi 	count = 0;
20007e3dbbacSRobert Mustacchi 	if (do_all)
20017e3dbbacSRobert Mustacchi 		count++;
20027e3dbbacSRobert Mustacchi 	if (platform != NULL)
20037e3dbbacSRobert Mustacchi 		count++;
20047e3dbbacSRobert Mustacchi 	if (count > 1) {
20057e3dbbacSRobert Mustacchi 		cpcgen_usage("Only one of -a and -p may be specified\n");
20067e3dbbacSRobert Mustacchi 		return (2);
20077e3dbbacSRobert Mustacchi 	} else if (count == 0) {
20087e3dbbacSRobert Mustacchi 		cpcgen_usage("One of -a and -p is required\n");
20097e3dbbacSRobert Mustacchi 		return (2);
20107e3dbbacSRobert Mustacchi 	}
20117e3dbbacSRobert Mustacchi 
20127e3dbbacSRobert Mustacchi 	if (outdir == NULL) {
20137e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required output directory (-o)\n");
20147e3dbbacSRobert Mustacchi 		return (2);
20157e3dbbacSRobert Mustacchi 	}
20167e3dbbacSRobert Mustacchi 
20177e3dbbacSRobert Mustacchi 	if ((outdirfd = open(outdir, O_RDONLY)) < 0) {
20187e3dbbacSRobert Mustacchi 		err(EXIT_FAILURE, "failed to open output directory %s", outdir);
20197e3dbbacSRobert Mustacchi 	}
20207e3dbbacSRobert Mustacchi 
20217e3dbbacSRobert Mustacchi 	if (datadir == NULL) {
20227e3dbbacSRobert Mustacchi 		cpcgen_usage("Missing required data directory (-d)\n");
20237e3dbbacSRobert Mustacchi 		return (2);
20247e3dbbacSRobert Mustacchi 	}
20257e3dbbacSRobert Mustacchi 
2026d0e58ef5SRobert Mustacchi 	cpcgen_determine_vendor(datadir);
2027d0e58ef5SRobert Mustacchi 
2028d0e58ef5SRobert Mustacchi 	switch (cpcgen_mode) {
2029d0e58ef5SRobert Mustacchi 	case CPCGEN_MODE_INTEL:
2030d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_gather = cpcgen_read_intel;
2031d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_common = cpcgen_common_intel_files;
2032d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_skip = cpcgen_skip_intel_entry;
2033d0e58ef5SRobert Mustacchi 		if (do_mpage) {
2034d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_name = cpcgen_manual_intel_name;
2035d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_before =
2036d0e58ef5SRobert Mustacchi 			    cpcgen_manual_intel_file_before;
2037d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_after =
2038d0e58ef5SRobert Mustacchi 			    cpcgen_manual_intel_file_after;
2039d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_event = cpcgen_manual_intel_event;
2040d0e58ef5SRobert Mustacchi 		} else {
2041d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_name = cpcgen_cfile_intel_name;
2042d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_before =
2043d0e58ef5SRobert Mustacchi 			    cpcgen_cfile_intel_before;
2044d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_after =
2045d0e58ef5SRobert Mustacchi 			    cpcgen_cfile_intel_after;
2046d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_event = cpcgen_cfile_intel_event;
2047d0e58ef5SRobert Mustacchi 		}
2048d0e58ef5SRobert Mustacchi 		break;
2049d0e58ef5SRobert Mustacchi 	case CPCGEN_MODE_AMD:
2050d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_gather = cpcgen_read_amd;
2051d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_common = cpcgen_common_amd_files;
2052d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_skip = NULL;
2053d0e58ef5SRobert Mustacchi 		if (do_mpage) {
2054d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_name = cpcgen_manual_amd_name;
2055d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_before =
2056d0e58ef5SRobert Mustacchi 			    cpcgen_manual_amd_file_before;
2057d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_after =
2058d0e58ef5SRobert Mustacchi 			    cpcgen_manual_amd_file_after;
2059d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_event = cpcgen_manual_amd_event;
2060d0e58ef5SRobert Mustacchi 		} else {
2061d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_name = cpcgen_cfile_amd_name;
2062d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_before =
2063d0e58ef5SRobert Mustacchi 			    cpcgen_cfile_amd_before;
2064d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_file_after = cpcgen_cfile_amd_after;
2065d0e58ef5SRobert Mustacchi 			cpcgen_ops.cgen_op_event = cpcgen_cfile_amd_event;
20667e3dbbacSRobert Mustacchi 
2067d0e58ef5SRobert Mustacchi 		}
2068d0e58ef5SRobert Mustacchi 		break;
2069d0e58ef5SRobert Mustacchi 	default:
2070d0e58ef5SRobert Mustacchi 		errx(EXIT_FAILURE, "failed to determine if operating on AMD or "
2071d0e58ef5SRobert Mustacchi 		    "Intel");
2072d0e58ef5SRobert Mustacchi 		break;
20737e3dbbacSRobert Mustacchi 	}
20747e3dbbacSRobert Mustacchi 
2075d0e58ef5SRobert Mustacchi 	cpcgen_ops.cgen_op_gather(datadir, platform);
20767e3dbbacSRobert Mustacchi 
2077d0e58ef5SRobert Mustacchi 	if (do_header) {
2078d0e58ef5SRobert Mustacchi 		cpcgen_ops.cgen_op_common(outdirfd);
2079d0e58ef5SRobert Mustacchi 		return (0);
20807e3dbbacSRobert Mustacchi 	}
20817e3dbbacSRobert Mustacchi 
20827e3dbbacSRobert Mustacchi 	cpcgen_gen(outdirfd);
20837e3dbbacSRobert Mustacchi 
20847e3dbbacSRobert Mustacchi 	return (0);
20857e3dbbacSRobert Mustacchi }
2086