Index: sys/geom/geom_flashmap.c =================================================================== --- sys/geom/geom_flashmap.c +++ sys/geom/geom_flashmap.c @@ -1,4 +1,6 @@ /*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * * Copyright (c) 2012 Semihalf * Copyright (c) 2009 Jakub Klama * All rights reserved. @@ -28,6 +30,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_geom.h" + #include #include #include @@ -44,6 +48,10 @@ #define FLASHMAP_CLASS_NAME "Flashmap" +#define FLASHMAP_UBOOTHDRSIZE 64 +#define FLASHMAP_SECTORSIZE (64 * 1024) +#define FLASHMAP_MARKER_STR "#!/bin/sh" + struct g_flashmap_slice { off_t sl_start; off_t sl_end; @@ -68,11 +76,13 @@ static g_taste_t g_flashmap_taste; static int g_flashmap_load(device_t dev, struct g_provider *pp, - flash_slicer_t slicer, struct g_flashmap_head *head); + struct g_consumer *cp, flash_slicer_t slicer, struct g_flashmap_head *head); static int g_flashmap_modify(struct g_geom *gp, const char *devname, int secsize, struct g_flashmap_head *slices); static void g_flashmap_print(struct g_flashmap_slice *slice); +static off_t chkuboothdr(struct g_consumer *cp, off_t offset); + MALLOC_DECLARE(M_FLASHMAP); MALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class"); @@ -181,7 +191,7 @@ if (slicer == NULL) break; - if (g_flashmap_load(dev, pp, slicer, &head) == 0) + if (g_flashmap_load(dev, pp, cp, slicer, &head) == 0) break; g_flashmap_modify(gp, cp->provider->name, @@ -200,13 +210,54 @@ return (gp); } +static off_t +chkuboothdr(struct g_consumer *cp, off_t offset) +{ + off_t val; + uint8_t *buf; + size_t sectorsize; + int i; + + sectorsize = FLASHMAP_SECTORSIZE; + sectorsize = cp->provider->sectorsize; + buf = g_read_data(cp, offset, sectorsize, NULL); + /* check u-boot header magic number */ + if (buf[0] != 0x27 || buf[1] != 0x05 || buf[2] != 0x19 || + buf[3] != 0x56) { + g_free(buf); + return 0; + } + /* get image data size */ + val = buf[0xc] << 24 | buf[0xd] << 16 | buf[0xe] << 8 | buf[0xf]; + val += FLASHMAP_UBOOTHDRSIZE; + val = (val - 1) / FLASHMAP_SECTORSIZE; + val = (val + 1) * FLASHMAP_SECTORSIZE; + g_free(buf); + /* check 64K and 128K boundly */ + for (i = 0; i < 2; ++i) { + buf = g_read_data(cp, offset + val, sectorsize, NULL); + if (strncmp(buf, FLASHMAP_MARKER_STR, + strlen(FLASHMAP_MARKER_STR)) == 0) + break; + g_free(buf); + val += FLASHMAP_SECTORSIZE; + } + if (i == 2) + return 0; + g_free(buf); + return offset + val; +} + static int -g_flashmap_load(device_t dev, struct g_provider *pp, flash_slicer_t slicer, - struct g_flashmap_head *head) +g_flashmap_load(device_t dev, struct g_provider *pp, struct g_consumer *cp, + flash_slicer_t slicer, struct g_flashmap_head *head) { struct flash_slice *slices; struct g_flashmap_slice *slice; int i, nslices = 0; + struct g_flashmap_slice *rootfs; + off_t rootfsbase; + char *rootfsname; slices = malloc(sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM, M_FLASHMAP, M_WAITOK | M_ZERO); @@ -218,8 +269,32 @@ slice->sl_name = slices[i].label; slice->sl_start = slices[i].base; slice->sl_end = slices[i].base + slices[i].size - 1; - - STAILQ_INSERT_TAIL(head, slice, sl_link); + if(strcmp("firmware", slice->sl_name) == 0) { + rootfsbase = chkuboothdr(cp, slice->sl_start); + if (rootfsbase != 0) { + rootfs = malloc(sizeof( + struct g_flashmap_slice), + M_FLASHMAP, M_WAITOK); + + slice->sl_end = rootfsbase - 1; + rootfsname = g_malloc(32, + M_WAITOK | M_ZERO); + strcpy(rootfsname, "rootfs"); + rootfs->sl_name = rootfsname; + rootfs->sl_start = rootfsbase; + rootfs->sl_end = slices[i].base + + slices[i].size - 1; + STAILQ_INSERT_TAIL(head, slice, + sl_link); + STAILQ_INSERT_TAIL(head, rootfs, + sl_link); + } else { + STAILQ_INSERT_TAIL(head, slice, + sl_link); + } + } else { + STAILQ_INSERT_TAIL(head, slice, sl_link); + } } }