1/*- 2 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: releng/11.0/sys/dev/bhnd/cores/chipc/chipc_slicer.c 302189 2016-06-25 04:33:00Z landonf $"); 32 33/* 34 * Slicer is required to split firmware images into pieces. 35 * The first supported FW is TRX-based used by Asus routers 36 * TODO: add NetGear FW (CHK) 37 */ 38 39#include <sys/param.h> 40#include <sys/kernel.h> 41#include <sys/module.h> 42#include <sys/errno.h> 43#include <sys/rman.h> 44#include <sys/bus.h> 45#include <sys/systm.h> 46#include <sys/slicer.h> 47 48#include <machine/bus.h> 49 50#include <dev/bhnd/bhnd_debug.h> 51 52#include "chipc_slicer.h" 53 54#include <dev/cfi/cfi_var.h> 55#include "chipc_spi.h" 56 57static int chipc_slicer_walk(device_t dev, struct resource *res, 58 struct flash_slice *slices, int *nslices); 59 60void 61chipc_register_slicer(chipc_flash flash_type) 62{ 63 switch (flash_type) { 64 case CHIPC_SFLASH_AT: 65 case CHIPC_SFLASH_ST: 66 flash_register_slicer(chipc_slicer_spi); 67 break; 68 case CHIPC_PFLASH_CFI: 69 flash_register_slicer(chipc_slicer_cfi); 70 break; 71 default: 72 /* Unsupported */ 73 break; 74 } 75} 76 77int 78chipc_slicer_cfi(device_t dev, struct flash_slice *slices, int *nslices) 79{ 80 struct cfi_softc *sc; 81 device_t parent; 82 83 /* must be CFI flash */ 84 if (device_get_devclass(dev) != devclass_find("cfi")) 85 return (ENXIO); 86 87 /* must be attached to chipc */ 88 if ((parent = device_get_parent(dev)) == NULL) { 89 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 90 return (ENXIO); 91 } 92 93 if (device_get_devclass(parent) != devclass_find("bhnd_chipc")) { 94 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 95 return (ENXIO); 96 } 97 98 sc = device_get_softc(dev); 99 return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices)); 100} 101 102int 103chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices) 104{ 105 struct chipc_spi_softc *sc; 106 device_t chipc, spi, spibus; 107 108 BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev)); 109 110 /* must be SPI-attached flash */ 111 spibus = device_get_parent(dev); 112 if (spibus == NULL) { 113 BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device"); 114 return (ENXIO); 115 } 116 117 spi = device_get_parent(spibus); 118 if (spi == NULL) { 119 BHND_ERROR_DEV(dev, "no found ChipCommon SPI device"); 120 return (ENXIO); 121 } 122 123 chipc = device_get_parent(spi); 124 if (device_get_devclass(chipc) != devclass_find("bhnd_chipc")) { 125 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 126 return (ENXIO); 127 } 128 129 sc = device_get_softc(spi); 130 return (chipc_slicer_walk(dev, sc->sc_flash_res, slices, nslices)); 131} 132 133/* 134 * Main processing part 135 */ 136static int 137chipc_slicer_walk(device_t dev, struct resource *res, 138 struct flash_slice *slices, int *nslices) 139{ 140 uint32_t fw_len; 141 uint32_t fs_ofs; 142 uint32_t val; 143 uint32_t ofs_trx; 144 int flash_size; 145 146 *nslices = 0; 147 148 flash_size = rman_get_size(res); 149 ofs_trx = flash_size; 150 151 BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...", 152 flash_size); 153 154 /* Find FW header in flash memory with step=128Kb (0x1000) */ 155 for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){ 156 val = bus_read_4(res, ofs); 157 switch (val) { 158 case TRX_MAGIC: 159 /* check for second TRX */ 160 if (ofs_trx < ofs) { 161 BHND_TRACE_DEV(dev, "stop on 2nd TRX: %x", ofs); 162 break; 163 } 164 165 BHND_TRACE("TRX found: %x", ofs); 166 ofs_trx = ofs; 167 /* read last offset of TRX header */ 168 fs_ofs = bus_read_4(res, ofs + 24); 169 BHND_TRACE("FS offset: %x", fs_ofs); 170 171 /* 172 * GEOM IO will panic if offset is not aligned 173 * on sector size, i.e. 512 bytes 174 */ 175 if (fs_ofs % 0x200 != 0) { 176 BHND_WARN("WARNING! filesystem offset should be" 177 " aligned on sector size (%d bytes)", 0x200); 178 BHND_WARN("ignoring TRX firmware image"); 179 break; 180 } 181 182 slices[*nslices].base = ofs + fs_ofs; 183 //XXX: fully sized? any other partition? 184 fw_len = bus_read_4(res, ofs + 4); 185 slices[*nslices].size = fw_len - fs_ofs; 186 slices[*nslices].label = "rootfs"; 187 *nslices += 1; 188 break; 189 case CFE_MAGIC: 190 BHND_TRACE("CFE found: %x", ofs); 191 break; 192 case NVRAM_MAGIC: 193 BHND_TRACE("NVRAM found: %x", ofs); 194 break; 195 default: 196 break; 197 } 198 } 199 200 BHND_TRACE("slicer: done"); 201 return (0); 202} 203