1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com> 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 /* 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 57 static int chipc_slicer_walk(device_t dev, struct resource *res, 58 struct flash_slice *slices, int *nslices); 59 60 void 61 chipc_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, FLASH_SLICES_TYPE_SPI, 67 TRUE); 68 break; 69 case CHIPC_PFLASH_CFI: 70 flash_register_slicer(chipc_slicer_cfi, FLASH_SLICES_TYPE_CFI, 71 TRUE); 72 break; 73 default: 74 /* Unsupported */ 75 break; 76 } 77 } 78 79 int 80 chipc_slicer_cfi(device_t dev, const char *provider __unused, 81 struct flash_slice *slices, int *nslices) 82 { 83 struct cfi_softc *sc; 84 device_t parent; 85 86 /* must be CFI flash */ 87 if (device_get_devclass(dev) != devclass_find("cfi")) 88 return (ENXIO); 89 90 /* must be attached to chipc */ 91 if ((parent = device_get_parent(dev)) == NULL) { 92 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 93 return (ENXIO); 94 } 95 96 if (device_get_devclass(parent) != devclass_find("bhnd_chipc")) { 97 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 98 return (ENXIO); 99 } 100 101 sc = device_get_softc(dev); 102 return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices)); 103 } 104 105 int 106 chipc_slicer_spi(device_t dev, const char *provider __unused, 107 struct flash_slice *slices, int *nslices) 108 { 109 struct chipc_spi_softc *sc; 110 device_t chipc, spi, spibus; 111 112 BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev)); 113 114 /* must be SPI-attached flash */ 115 spibus = device_get_parent(dev); 116 if (spibus == NULL) { 117 BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device"); 118 return (ENXIO); 119 } 120 121 spi = device_get_parent(spibus); 122 if (spi == NULL) { 123 BHND_ERROR_DEV(dev, "no found ChipCommon SPI device"); 124 return (ENXIO); 125 } 126 127 chipc = device_get_parent(spi); 128 if (device_get_devclass(chipc) != devclass_find("bhnd_chipc")) { 129 BHND_ERROR_DEV(dev, "no found ChipCommon device"); 130 return (ENXIO); 131 } 132 133 sc = device_get_softc(spi); 134 return (chipc_slicer_walk(dev, sc->sc_flash_res, slices, nslices)); 135 } 136 137 /* 138 * Main processing part 139 */ 140 static int 141 chipc_slicer_walk(device_t dev, struct resource *res, 142 struct flash_slice *slices, int *nslices) 143 { 144 uint32_t fw_len; 145 uint32_t fs_ofs; 146 uint32_t val; 147 uint32_t ofs_trx; 148 int flash_size; 149 150 *nslices = 0; 151 152 flash_size = rman_get_size(res); 153 ofs_trx = flash_size; 154 155 BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...", 156 flash_size); 157 158 /* Find FW header in flash memory with step=128Kb (0x1000) */ 159 for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){ 160 val = bus_read_4(res, ofs); 161 switch (val) { 162 case TRX_MAGIC: 163 /* check for second TRX */ 164 if (ofs_trx < ofs) { 165 BHND_TRACE_DEV(dev, "stop on 2nd TRX: %x", ofs); 166 break; 167 } 168 169 BHND_TRACE("TRX found: %x", ofs); 170 ofs_trx = ofs; 171 /* read last offset of TRX header */ 172 fs_ofs = bus_read_4(res, ofs + 24); 173 BHND_TRACE("FS offset: %x", fs_ofs); 174 175 /* 176 * GEOM IO will panic if offset is not aligned 177 * on sector size, i.e. 512 bytes 178 */ 179 if (fs_ofs % 0x200 != 0) { 180 BHND_WARN("WARNING! filesystem offset should be" 181 " aligned on sector size (%d bytes)", 0x200); 182 BHND_WARN("ignoring TRX firmware image"); 183 break; 184 } 185 186 slices[*nslices].base = ofs + fs_ofs; 187 //XXX: fully sized? any other partition? 188 fw_len = bus_read_4(res, ofs + 4); 189 slices[*nslices].size = fw_len - fs_ofs; 190 slices[*nslices].label = "rootfs"; 191 *nslices += 1; 192 break; 193 case CFE_MAGIC: 194 BHND_TRACE("CFE found: %x", ofs); 195 break; 196 case NVRAM_MAGIC: 197 BHND_TRACE("NVRAM found: %x", ofs); 198 break; 199 default: 200 break; 201 } 202 } 203 204 BHND_TRACE("slicer: done"); 205 return (0); 206 } 207