geom_map.c revision 220559
1/*- 2 * Copyright (c) 2010-2011 Aleksandr Rybalko <ray@dlink.ua> 3 * based on geom_redboot.c 4 * Copyright (c) 2009 Sam Leffler, Errno Consulting 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer, 12 * without modification. 13 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15 * redistribution must be conditioned upon including a substantially 16 * similar Disclaimer requirement for further binary redistribution. 17 * 18 * NO WARRANTY 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29 * THE POSSIBILITY OF SUCH DAMAGES. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sys/geom/geom_map.c 220559 2011-04-12 08:10:25Z adrian $"); 34 35#include <sys/param.h> 36#include <sys/bus.h> 37#include <sys/errno.h> 38#include <sys/endian.h> 39#include <sys/systm.h> 40#include <sys/kernel.h> 41#include <sys/fcntl.h> 42#include <sys/malloc.h> 43#include <sys/bio.h> 44#include <sys/lock.h> 45#include <sys/mutex.h> 46 47#include <sys/sbuf.h> 48#include <geom/geom.h> 49#include <geom/geom_slice.h> 50 51#define MAP_CLASS_NAME "MAP" 52 53struct map_desc { 54 uint8_t name [16]; /* null-terminated name */ 55 uint32_t offset; /* offset in flash */ 56 uint32_t addr; /* address in memory */ 57 uint32_t size; /* image size in bytes */ 58 uint32_t entry; /* offset in image for entry point */ 59 uint32_t dsize; /* data size in bytes */ 60}; 61 62#define MAP_MAXSLICE 64 63 64struct g_map_softc { 65 uint32_t entry [MAP_MAXSLICE]; 66 uint32_t dsize [MAP_MAXSLICE]; 67 uint8_t readonly[MAP_MAXSLICE]; 68 g_access_t *parent_access; 69}; 70 71static int 72g_map_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td) 73{ 74 return (ENOIOCTL); 75} 76 77static int 78g_map_access(struct g_provider *pp, int dread, int dwrite, int dexcl) 79{ 80 struct g_geom *gp = pp->geom; 81 struct g_slicer *gsp = gp->softc; 82 struct g_map_softc *sc = gsp->softc; 83 84 if (dwrite > 0 && sc->readonly[pp->index]) 85 return (EPERM); 86 return (sc->parent_access(pp, dread, dwrite, dexcl)); 87 /* 88 * no (sc->parent_access(pp, dread, dwrite, dexcl));, 89 * We need to have way for update flash 90 */ 91} 92 93static int 94g_map_start(struct bio *bp) 95{ 96 struct g_provider *pp; 97 struct g_geom *gp; 98 struct g_map_softc *sc; 99 struct g_slicer *gsp; 100 int idx; 101 102 pp = bp->bio_to; 103 idx = pp->index; 104 gp = pp->geom; 105 gsp = gp->softc; 106 sc = gsp->softc; 107 if (bp->bio_cmd == BIO_GETATTR) { 108 if (g_handleattr_int(bp, MAP_CLASS_NAME "::entry", 109 sc->entry[idx])) 110 return (1); 111 if (g_handleattr_int(bp, MAP_CLASS_NAME "::dsize", 112 sc->dsize[idx])) 113 return (1); 114 } 115 return (0); 116} 117 118static void 119g_map_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 120 struct g_consumer *cp __unused, struct g_provider *pp) 121{ 122 struct g_map_softc *sc; 123 struct g_slicer *gsp; 124 125 gsp = gp->softc; 126 sc = gsp->softc; 127 g_slice_dumpconf(sb, indent, gp, cp, pp); 128 if (pp != NULL) { 129 if (indent == NULL) { 130 sbuf_printf(sb, " entry %d", sc->entry[pp->index]); 131 sbuf_printf(sb, " dsize %d", sc->dsize[pp->index]); 132 } else { 133 sbuf_printf(sb, "%s<entry>%d</entry>\n", indent, 134 sc->entry[pp->index]); 135 sbuf_printf(sb, "%s<dsize>%d</dsize>\n", indent, 136 sc->dsize[pp->index]); 137 } 138 } 139} 140 141#include <sys/ctype.h> 142 143 144static struct g_geom * 145g_map_taste(struct g_class *mp, struct g_provider *pp, int insist) 146{ 147 struct g_geom *gp; 148 struct g_consumer *cp; 149 struct g_map_softc *sc; 150 int error , sectorsize, i, ret; 151 struct map_desc *head; 152 u_int32_t start = 0, end = 0, size = 0, off, readonly; 153 const char *name; 154 const char *at; 155 const char *search; 156 int search_start = 0, search_end = 0; 157 u_char *buf; 158 uint32_t offmask; 159 u_int blksize;/* NB: flash block size stored as stripesize */ 160 off_t offset; 161 162 g_trace(G_T_TOPOLOGY, "map_taste(%s,%s)", mp->name, pp->name); 163 g_topology_assert(); 164 if (!strcmp(pp->geom->class->name, MAP_CLASS_NAME)) 165 return (NULL); 166 167 gp = g_slice_new(mp, MAP_MAXSLICE, pp, &cp, &sc, sizeof(*sc), 168 g_map_start); 169 if (gp == NULL) 170 return (NULL); 171 172 /* interpose our access method */ 173 sc->parent_access = gp->access; 174 gp->access = g_map_access; 175 176 sectorsize = cp->provider->sectorsize; 177 blksize = cp->provider->stripesize; 178 if (powerof2(cp->provider->mediasize)) 179 offmask = cp->provider->mediasize - 1; 180 else 181 offmask = 0xffffffff; /* XXX */ 182 183 g_topology_unlock(); 184 head = NULL; 185 offset = cp->provider->mediasize - blksize; 186 g_topology_lock(); 187 188 for (i = 0; i < MAP_MAXSLICE; i++) { 189 search_start = search_end = start = end = off = readonly = 0; 190 191 ret = resource_string_value("map", i, "at", &at); 192 if (ret) 193 continue; 194 195 /* Check if my provider */ 196 if (strncmp(pp->name, at, strlen(at))) 197 continue; 198 199 ret = resource_string_value("map", i, "start", &search); 200 201 if (!ret && strncmp(search, "search", 6) == 0) { 202 uint32_t search_offset, search_start = 0; 203 uint32_t search_step = 0; 204 const char *search_key; 205 char key[255]; 206 int c; 207 208 ret = resource_int_value("map", i, "searchstart", 209 &search_start); 210 ret = resource_int_value("map", i, "searchstep", 211 &search_step); 212 if (ret) 213 search_step = 0x10000U; 214 ret = resource_string_value("map", i, "searchkey", &search_key); 215 if (ret) 216 continue; 217 218 printf("GEOM_MAP: searchkey=\"%s\"\n", search_key); 219 for (search_offset = search_start; 220 search_offset < cp->provider->mediasize && start == 0; 221 search_offset += search_step) { 222 buf = g_read_data(cp, 223 rounddown(search_offset, sectorsize), 224 roundup(strlen(search_key), sectorsize), 225 NULL); 226 227 /* Wildcard, replace '.' with byte from data */ 228 strncpy(key, search_key, 255); 229 for (c = 0; c < 255 && key[c]; c++) 230 if (key[c] == '.') 231 key[c] = ((char *)(buf + search_offset % sectorsize))[c]; 232 233 if (buf != NULL && strncmp( 234 buf + search_offset % sectorsize, 235 key, strlen(search_key)) == 0) 236 start = search_offset; 237 g_free(buf); 238 } 239 if (!start) 240 continue; 241 } else { 242 ret = resource_int_value("map", i, "start", &start); 243 if (ret) 244 continue; 245 } 246 247 ret = resource_string_value("map", i, "end", &search); 248 249 if (!ret && strncmp(search, "search", 6) == 0) { 250 uint32_t search_offset, search_start = 0, search_step = 0; 251 const char *search_key; 252 char key[255]; 253 int c; 254 255 ret = resource_int_value("map", i, "searchstart", &search_start); 256 ret = resource_int_value("map", i, "searchstep", &search_step); 257 if (ret) 258 search_step = 0x10000U; 259 ret = resource_string_value("map", i, "searchkey", &search_key); 260 if (ret) 261 continue; 262 263 for (search_offset = search_start; 264 search_offset < cp->provider->mediasize && end == 0; 265 search_offset += search_step) { 266 buf = g_read_data(cp, 267 rounddown(search_offset, sectorsize), 268 roundup(strlen(search_key), sectorsize), 269 NULL); 270 271 /* Wildcard, replace '.' with byte from data */ 272 strncpy(key, search_key, 255); 273 for (c = 0; c < 255 && key[c]; c++) 274 if (key[c] == '.') 275 key[c] = ((char *)(buf + search_offset % sectorsize))[c]; 276 277 if (buf != NULL && strncmp( 278 buf + search_offset % sectorsize, 279 key, strlen(search_key)) == 0) 280 end = search_offset; 281 g_free(buf); 282 } 283 if (!end) 284 continue; 285 } else { 286 ret = resource_int_value("map", i, "end", &end); 287 if (ret) 288 continue; 289 } 290 size = end - start; 291 292 /* end is 0 or size is 0, No MAP - so next */ 293 if (end == 0 || size == 0) 294 continue; 295 ret = resource_int_value("map", i, "offset", &off); 296 ret = resource_int_value("map", i, "readonly", &readonly); 297 ret = resource_string_value("map", i, "name", &name); 298 /* No name or error read name */ 299 if (ret) 300 continue; 301 302 if (off > size) 303 printf("%s: off(%d) > size(%d) for \"%s\"\n", 304 __func__, off, size, name); 305 306 error = g_slice_config(gp, i, G_SLICE_CONFIG_SET, start + off, 307 size - off, sectorsize, "map/%s", name); 308 printf("MAP: %08x-%08x, offset=%08x \"map/%s\"\n", 309 (uint32_t) start, 310 (uint32_t) size, 311 (uint32_t) off, 312 name 313 ); 314 315 if (error) 316 printf("%s g_slice_config returns %d for \"%s\"\n", 317 __func__, error, name); 318 319 sc->entry[i] = off; 320 sc->dsize[i] = size - off; 321 sc->readonly[i] = readonly ? 1 : 0; 322 } 323 324 325 if (i == 0) 326 return (NULL); 327 328 g_access(cp, -1, 0, 0); 329 if (LIST_EMPTY(&gp->provider)) { 330 g_slice_spoiled(cp); 331 return (NULL); 332 } 333 return (gp); 334} 335 336static void 337g_map_config(struct gctl_req *req, struct g_class *mp, const char *verb) 338{ 339 struct g_geom *gp; 340 341 g_topology_assert(); 342 gp = gctl_get_geom(req, mp, "geom"); 343 if (gp == NULL) 344 return; 345 gctl_error(req, "Unknown verb"); 346} 347 348static struct g_class g_map_class = { 349 .name = MAP_CLASS_NAME, 350 .version = G_VERSION, 351 .taste = g_map_taste, 352 .dumpconf = g_map_dumpconf, 353 .ctlreq = g_map_config, 354 .ioctl = g_map_ioctl, 355}; 356DECLARE_GEOM_CLASS(g_map_class, g_map); 357