1 /* $OpenBSD: dev.c,v 1.11 2020/12/09 18:10:19 krw Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Miodrag Vallat. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 /*- 19 * Copyright (c) 2003 The NetBSD Foundation, Inc. 20 * All rights reserved. 21 * 22 * This code is derived from software contributed to The NetBSD Foundation 23 * by Manuel Bouyer. 24 * 25 * Redistribution and use in source and binary forms, with or without 26 * modification, are permitted provided that the following conditions 27 * are met: 28 * 1. Redistributions of source code must retain the above copyright 29 * notice, this list of conditions and the following disclaimer. 30 * 2. Redistributions in binary form must reproduce the above copyright 31 * notice, this list of conditions and the following disclaimer in the 32 * documentation and/or other materials provided with the distribution. 33 * 34 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 35 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 44 * POSSIBILITY OF SUCH DAMAGE. 45 */ 46 47 #include <sys/param.h> 48 #include "libsa.h" 49 #include <sys/disklabel.h> 50 #include <machine/cpu.h> 51 #include <machine/pmon.h> 52 53 /* 54 * PMON I/O 55 */ 56 57 char pmon_bootdev[1 + 256]; 58 59 struct pmon_iodata { 60 int fd; 61 struct disklabel label; 62 off_t partoff; 63 off_t curpos; 64 }; 65 66 int pmon_getdisklabel(struct pmon_iodata *pi); 67 68 int 69 pmon_iostrategy(void *f, int rw, daddr_t dblk, size_t size, void *buf, 70 size_t *rsize) 71 { 72 struct pmon_iodata *pi = (struct pmon_iodata *)f; 73 off_t offs, pos; 74 int rc; 75 76 if (rsize != NULL) 77 *rsize = 0; 78 if (size == 0) 79 return 0; 80 81 if (rw != F_READ) 82 return EOPNOTSUPP; 83 84 offs = ((daddr_t)dblk + pi->partoff) * DEV_BSIZE; 85 if (offs != pi->curpos) { 86 pos = pmon_lseek(pi->fd, offs, 0 /* SEEK_SET */); 87 if (pos != offs) 88 return EINVAL; 89 } 90 91 /* note this expects size to fit in 32 bits */ 92 rc = pmon_read(pi->fd, buf, size); 93 if (rc >= 0) { 94 pi->curpos += rc; 95 if (rsize != NULL) 96 *rsize = rc; 97 } 98 99 if (rc != size) 100 return EIO; 101 return 0; 102 } 103 104 int 105 pmon_ioopen(struct open_file *f, ...) 106 { 107 static const u_char zero[8] = { 0 }; 108 struct pmon_iodata *pi; 109 int rc; 110 va_list ap; 111 uint unit, part; 112 113 pi = alloc(sizeof *pi); 114 if (pi == NULL) 115 return ENOMEM; 116 bzero(pi, sizeof *pi); 117 f->f_devdata = pi; 118 119 va_start(ap, f); 120 unit = va_arg(ap, uint); 121 part = va_arg(ap, uint); 122 va_end(ap); 123 124 /* 125 * Open the raw device through PMON. 126 */ 127 128 snprintf(pmon_bootdev, sizeof pmon_bootdev, "/dev/disk/%s%d", 129 f->f_dev->dv_name, unit); 130 rc = pmon_open(pmon_bootdev, 0 /* O_RDONLY */); 131 if (rc < 0) 132 return ENXIO; 133 134 pi->fd = rc; 135 136 /* 137 * Read disklabel. 138 */ 139 140 if (pmon_getdisklabel(pi) != 0) { 141 pmon_ioclose(f); 142 return ENXIO; 143 } 144 145 if (part >= pi->label.d_npartitions) { 146 pmon_ioclose(f); 147 return EPART; 148 } 149 150 if (memcmp(pi->label.d_uid, zero, sizeof(pi->label.d_uid)) != 0) { 151 const u_char *duid = pi->label.d_uid; 152 153 snprintf(pmon_bootdev, sizeof(pmon_bootdev), 154 "bootduid=%02x%02x%02x%02x%02x%02x%02x%02x", 155 duid[0], duid[1], duid[2], duid[3], 156 duid[4], duid[5], duid[6], duid[7]); 157 } 158 159 pi->partoff = DL_GETPOFFSET(&pi->label.d_partitions[part]); 160 pi->curpos = 0; 161 162 return 0; 163 } 164 165 int 166 pmon_ioclose(struct open_file *f) 167 { 168 struct pmon_iodata *pi; 169 int rc; 170 171 if (f->f_devdata != NULL) { 172 pi = (struct pmon_iodata *)f->f_devdata; 173 rc = pmon_close(pi->fd); 174 free(pi, sizeof *pi); 175 f->f_devdata = NULL; 176 } else 177 rc = 0; 178 179 return rc; 180 } 181 182 /* 183 * Read disk label from the device. 184 */ 185 int 186 pmon_getdisklabel(struct pmon_iodata *pi) 187 { 188 char *msg; 189 int sector; 190 size_t rsize; 191 struct disklabel *lp = &pi->label; 192 char buf[DEV_BSIZE]; 193 194 bzero(lp, sizeof *lp); 195 196 /* 197 * Find OpenBSD Partition in DOS partition table. 198 */ 199 sector = 0; 200 if (pmon_iostrategy(pi, F_READ, DOSBBSECTOR, DEV_BSIZE, buf, &rsize)) 201 return ENXIO; 202 203 if (*(u_int16_t *)&buf[DOSMBR_SIGNATURE_OFF] == DOSMBR_SIGNATURE) { 204 int i; 205 struct dos_partition *dp = (struct dos_partition *)buf; 206 207 /* 208 * Lookup OpenBSD slice. If there is none, go ahead 209 * and try to read the disklabel off sector #0. 210 */ 211 memcpy(dp, &buf[DOSPARTOFF], NDOSPART * sizeof(*dp)); 212 for (i = 0; i < NDOSPART; i++) { 213 if (dp[i].dp_typ == DOSPTYP_OPENBSD) { 214 sector = letoh32(dp[i].dp_start); 215 break; 216 } 217 } 218 } 219 220 if (pmon_iostrategy(pi, F_READ, sector + DOS_LABELSECTOR, DEV_BSIZE, 221 buf, &rsize)) 222 return ENXIO; 223 224 if ((msg = getdisklabel(buf + LABELOFFSET, lp))) { 225 printf("getdisklabel: %s\n", msg); 226 return ENXIO; 227 } 228 229 return 0; 230 } 231