1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2020 Oxide Computer Company 14 */ 15 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <fcntl.h> 19 #include <errno.h> 20 #include <sys/mdb_modapi.h> 21 #include <sys/smbios_impl.h> 22 #include <unistd.h> 23 24 /* 25 * Unfortunately, we're in a bit of a bind. Because of the situation we're in, 26 * we cannot use string.h directly as it declares ffs() which is also declared 27 * in sys/systm.h. sys/systm.h is being pulled in because mdb is building with 28 * _KERNEL. Therefore we have to manually declare an extern delaration for 29 * strerror(). 30 */ 31 extern char *strerror(int); 32 33 /* 34 * Take an existing smbios_hdl_t from a dump and slurp out its memory so we can 35 * open up a new smbios handle to perform operations on. 36 */ 37 static int 38 smbios_mdb_write(const char *path, uintptr_t addr) 39 { 40 smbios_hdl_t shp, *hdl; 41 void *buf; 42 int err, fd = -1; 43 int ret = DCMD_ERR; 44 45 if (mdb_vread(&shp, sizeof (shp), addr) != sizeof (shp)) { 46 mdb_warn("failed to read smbios_hdl_t at %p", addr); 47 return (DCMD_ERR); 48 } 49 50 buf = mdb_alloc(shp.sh_buflen, UM_NOSLEEP | UM_GC); 51 if (buf == NULL) { 52 mdb_warn("failed to allocate %zu bytes for the smbios " 53 "data buffer", shp.sh_buflen); 54 return (DCMD_ERR); 55 } 56 57 if (mdb_vread(buf, shp.sh_buflen, (uintptr_t)shp.sh_buf) != 58 shp.sh_buflen) { 59 mdb_warn("failed to copy smbios data at %p", shp.sh_buf); 60 return (DCMD_ERR); 61 } 62 63 hdl = smbios_bufopen(&shp.sh_ent, buf, shp.sh_buflen, SMB_VERSION, 0, 64 &err); 65 if (hdl == NULL) { 66 mdb_warn("failed to load smbios data: %s\n", 67 smbios_errmsg(err)); 68 return (DCMD_ERR); 69 } 70 71 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { 72 mdb_warn("failed to open output file %s: %s\n", path, 73 strerror(errno)); 74 goto out; 75 } 76 77 if (smbios_write(hdl, fd) != 0) { 78 mdb_warn("failed to write smbios data to %s: %s\n", path, 79 smbios_errmsg(smbios_errno(hdl))); 80 ret = DCMD_ERR; 81 } else { 82 ret = DCMD_OK; 83 } 84 out: 85 if (fd != -1) { 86 (void) close(fd); 87 } 88 smbios_close(hdl); 89 return (ret); 90 } 91 92 static int 93 smbios_mdb_smbios(uintptr_t addr, uint_t flags, int argc, 94 const mdb_arg_t *argv) 95 { 96 const char *wpath = NULL; 97 98 if (!(flags & DCMD_ADDRSPEC)) { 99 mdb_warn("missing required smbios_hdl_t\n"); 100 return (DCMD_USAGE); 101 } 102 103 if (mdb_getopts(argc, argv, 'w', MDB_OPT_STR, &wpath, NULL) != argc) { 104 return (DCMD_USAGE); 105 } 106 107 if (wpath != NULL) { 108 return (smbios_mdb_write(wpath, addr)); 109 } 110 111 return (DCMD_USAGE); 112 } 113 114 static void 115 smbios_mdb_help(void) 116 { 117 mdb_printf("Given a pointer to an smbios_hdl_t take the following " 118 "actions:\n\n" 119 "\t-w path\t\tWrite SMBIOS data out to path\n"); 120 } 121 122 static const mdb_dcmd_t smbios_dcmds[] = { 123 { "smbios", ":[-w path]", "Manipulate an smbios handle", 124 smbios_mdb_smbios, smbios_mdb_help }, 125 { NULL } 126 }; 127 128 static const mdb_modinfo_t smbios_modinfo = { 129 MDB_API_VERSION, smbios_dcmds, NULL 130 }; 131 132 const mdb_modinfo_t * 133 _mdb_init(void) 134 { 135 return (&smbios_modinfo); 136 } 137