static void *spi_flash_read(FlashOps *me, uint32_t offset, uint32_t size) { SpiFlash *flash = container_of(me, SpiFlash, ops); uint8_t *data = flash->cache + offset; assert(offset + size <= flash->rom_size); if (flash->spi->start(flash->spi)) { printf("%s: Failed to start flash transaction.\n", __func__); return NULL; } uint32_t command = swap_bytes32((ReadCommand << 24) | offset); if (flash->spi->transfer(flash->spi, NULL, &command, sizeof(command))) { printf("%s: Failed to send read command.\n", __func__); flash->spi->stop(flash->spi); return NULL; } if (flash->spi->transfer(flash->spi, data, NULL, size)) { printf("%s: Failed to receive %u bytes.\n", __func__, size); flash->spi->stop(flash->spi); return NULL; } if (flash->spi->stop(flash->spi)) { printf("%s: Failed to stop transaction.\n", __func__); return NULL; } return data; }
static uint64_t swap_bytes64(uint64_t i) { uint64_t res = swap_bytes32(i); res <<= 32; res |= swap_bytes32(i >> 32); return res; }
void fix_endianness(globals_t *vars, value_t *data_value) { if (!vars->options.reverse_endianness) { return; } if (data_value->flags.u64b) { data_value->uint64_value = swap_bytes64(data_value->uint64_value); } else if (data_value->flags.u32b) { data_value->uint32_value = swap_bytes32(data_value->uint32_value); } else if (data_value->flags.u16b) { data_value->uint16_value = swap_bytes16(data_value->uint16_value); } return; }
// swap endianness of 2, 4 or 8 byte word in-place. void swap_bytes_var(void *p, size_t num) { switch (num) { case sizeof(uint16_t): ; // empty statement to cheat the compiler uint16_t i16 = swap_bytes16(*((uint16_t *)p)); memcpy(p, &i16, sizeof(uint16_t)); return; case sizeof(uint32_t): ; uint32_t i32 = swap_bytes32(*((uint32_t *)p)); memcpy(p, &i32, sizeof(uint32_t)); return; case sizeof(uint64_t): ; uint64_t i64 = swap_bytes64(*((uint64_t *)p)); memcpy(p, &i64, sizeof(uint64_t)); return; } assert(false); return; }
/* * Write or erase the flash. To write, pass a buffer and size; to erase, * pass null for the buffer. * This function is guaranteed to be invoked with data not spanning across * writeable/erasable boundaries (page size/block size). */ static int spi_flash_modify(SpiFlash *flash, const void *buffer, uint32_t offset, uint32_t size, uint8_t opcode, const char *opname) { union { uint8_t bytes[4]; // We're using 3 byte addresses. uint32_t whole; } command; int stop_needed = 0; uint32_t rv = -1; do { /* Each write or erase command requires a 'write enable' (WREN) * first. */ if (flash->spi->start(flash->spi)) { printf("%s: Failed to start WREN transaction.\n", __func__); break; } command.bytes[0] = WriteEnableCommand; if (flash->spi->transfer(flash->spi, NULL, &command, 1)) { printf("%s: Failed to send write enable command.\n", __func__); stop_needed = 1; break; } /* * CS needs to be deasserted before any other command can be * issued after WREN. */ if (toggle_cs(flash, "WREN")) break; stop_needed = 1; command.whole = swap_bytes32((opcode << 24) | offset); if (flash->spi->transfer(flash->spi, NULL, &command, 4)) { printf("%s: Failed to send %s command.\n", __func__, opname); break; } if (buffer && flash->spi->transfer(flash->spi, NULL, buffer, size)) { printf("%s: Failed to write data.\n", __func__); break; } stop_needed = 1; if (!operation_failed(flash, opname)) rv = size; } while(0); if (stop_needed && flash->spi->stop(flash->spi)) printf("%s: Failed to stop.\n", __func__); return rv; }