1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "SpiFlash.h"
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <fstream>
21 #include <iostream>
22 #include <vector>
23 #include <string>
24
25 #include "sdkconfig.h"
26 #include "esp_flash_partitions.h"
27
28 using namespace std;
29
30 #define DIV_AND_CEIL(x, y) ((x) / (y) + ((x) % (y) > 0))
31
SpiFlash()32 SpiFlash::SpiFlash()
33 {
34 return;
35 }
36
~SpiFlash()37 SpiFlash::~SpiFlash()
38 {
39 deinit();
40 }
41
init(uint32_t chip_size,uint32_t block_size,uint32_t sector_size,uint32_t page_size,const char * partitions_bin)42 void SpiFlash::init(uint32_t chip_size, uint32_t block_size, uint32_t sector_size, uint32_t page_size, const char* partitions_bin)
43 {
44 // De-initialize first
45 deinit();
46
47 // Initialize values and alloc memory
48 this->chip_size = chip_size;
49 this->block_size = block_size;
50 this->sector_size = sector_size;
51 this->page_size = page_size;
52
53 this->blocks = DIV_AND_CEIL(this->chip_size, this->block_size);
54 this->sectors = DIV_AND_CEIL(this->chip_size, this->sector_size);
55 this->pages = DIV_AND_CEIL(this->chip_size, this->page_size);
56
57 this->erase_cycles = (uint32_t*) calloc(this->sectors, sizeof(uint32_t));
58 this->erase_states = (bool*) calloc(this->sectors, sizeof(bool));
59 memset(this->erase_states, 0xFF, this->sectors * sizeof(bool));
60
61 this->total_erase_cycles_limit = 0;
62 this->erase_cycles_limit = 0;
63
64 this->total_erase_cycles = 0;
65
66 // Load partitions table bin
67 this->memory = (uint8_t *) malloc(this->chip_size);
68 memset(this->memory, 0xFF, this->chip_size);
69
70 ifstream ifd(partitions_bin, ios::binary | ios::ate);
71 int size = ifd.tellg();
72
73 ifd.seekg(0, ios::beg);
74 vector<char> buffer;
75
76 buffer.resize(size);
77
78 ifd.read(buffer.data(), size);
79
80 memcpy(&this->memory[CONFIG_PARTITION_TABLE_OFFSET], buffer.data(), buffer.size());
81 }
82
deinit()83 void SpiFlash::deinit()
84 {
85 // Free all allocated memory
86 free(this->memory);
87
88 free(this->erase_cycles);
89 free(this->erase_states);
90 }
91
get_chip_size()92 uint32_t SpiFlash::get_chip_size()
93 {
94 return this->chip_size;
95 }
96
get_block_size()97 uint32_t SpiFlash::get_block_size()
98 {
99 return this->block_size;
100 }
101
get_sector_size()102 uint32_t SpiFlash::get_sector_size()
103 {
104 return this->sector_size;
105 }
106
get_page_size()107 uint32_t SpiFlash::get_page_size()
108 {
109 return this->page_size;
110 }
111
erase_block(uint32_t block)112 esp_rom_spiflash_result_t SpiFlash::erase_block(uint32_t block)
113 {
114 uint32_t sectors_per_block = (this->block_size / this->sector_size);
115 uint32_t start_sector = block * sectors_per_block;
116
117 for (int i = start_sector; i < start_sector + sectors_per_block; i++) {
118 this->erase_sector(i);
119 }
120
121 return ESP_ROM_SPIFLASH_RESULT_OK;
122 }
123
erase_sector(uint32_t sector)124 esp_rom_spiflash_result_t SpiFlash::erase_sector(uint32_t sector)
125 {
126 if (this->total_erase_cycles_limit != 0 &&
127 this->total_erase_cycles >= this->total_erase_cycles_limit) {
128 return ESP_ROM_SPIFLASH_RESULT_ERR;
129 }
130
131 if (this->erase_cycles_limit != 0 &&
132 this->erase_cycles[sector] >= this->erase_cycles_limit) {
133 return ESP_ROM_SPIFLASH_RESULT_ERR;
134 }
135
136 uint32_t pages_per_sector = (this->sector_size / this->page_size);
137 uint32_t start_page = sector * pages_per_sector;
138
139 if (this->erase_states[sector]) {
140 goto out;
141 }
142
143 for (int i = start_page; i < start_page + pages_per_sector; i++) {
144 this->erase_page(i);
145 }
146
147 this->erase_cycles[sector]++;
148 this->total_erase_cycles++;
149
150 this->erase_states[sector] = true;
151
152 out:
153 return ESP_ROM_SPIFLASH_RESULT_OK;
154 }
155
erase_page(uint32_t page)156 esp_rom_spiflash_result_t SpiFlash::erase_page(uint32_t page)
157 {
158 memset(&this->memory[page * this->page_size], 0xFF, this->page_size);
159 return ESP_ROM_SPIFLASH_RESULT_OK;
160 }
161
write(uint32_t dest_addr,const void * src,uint32_t size)162 esp_rom_spiflash_result_t SpiFlash::write(uint32_t dest_addr, const void *src, uint32_t size)
163 {
164 // Update reset states and check for failure
165 int start = 0;
166 int end = 0;
167
168 if (this->total_erase_cycles_limit != 0 &&
169 this->total_erase_cycles >= this->total_erase_cycles_limit) {
170 return ESP_ROM_SPIFLASH_RESULT_ERR;
171 }
172
173 start = dest_addr / this->get_sector_size();
174 end = size > 0 ? (dest_addr + size - 1) / this->get_sector_size() : start;
175
176 for (int i = start; i <= end; i++) {
177 if (this->erase_cycles_limit != 0 &&
178 this->erase_cycles[i] >= this->erase_cycles_limit) {
179 return ESP_ROM_SPIFLASH_RESULT_ERR;
180 }
181
182 this->erase_states[i] = false;
183 }
184
185 // Do the write
186 for(uint32_t ctr = 0; ctr < size; ctr++)
187 {
188 uint8_t data = ((uint8_t*)src)[ctr];
189 uint8_t written = this->memory[dest_addr + ctr];
190
191 // Emulate inability to set programmed bits without erasing
192 data &= written;
193
194 this->memory[dest_addr + ctr] = data;
195 }
196
197 return ESP_ROM_SPIFLASH_RESULT_OK;
198 }
199
read(uint32_t src_addr,void * dest,uint32_t size)200 esp_rom_spiflash_result_t SpiFlash::read(uint32_t src_addr, void *dest, uint32_t size)
201 {
202 // Check for failure
203 int start = 0;
204 int end = 0;
205
206 if (this->total_erase_cycles_limit != 0 &&
207 this->total_erase_cycles >= this->total_erase_cycles_limit) {
208 return ESP_ROM_SPIFLASH_RESULT_ERR;
209 }
210
211 start = src_addr / this->get_sector_size();
212 end = size > 0 ? (src_addr + size - 1) / this->get_sector_size() : start;
213
214 for (int i = start; i <= end; i++) {
215 if (this->erase_cycles_limit != 0 &&
216 this->erase_cycles[i] >= this->erase_cycles_limit) {
217 return ESP_ROM_SPIFLASH_RESULT_ERR;
218 }
219 }
220
221 // Do the read
222 memcpy(dest, &this->memory[src_addr], size);
223 return ESP_ROM_SPIFLASH_RESULT_OK;
224 }
225
get_memory_ptr(uint32_t src_address)226 uint8_t* SpiFlash::get_memory_ptr(uint32_t src_address)
227 {
228 return &this->memory[src_address];
229 }
230
get_erase_cycles(uint32_t sector)231 uint32_t SpiFlash::get_erase_cycles(uint32_t sector)
232 {
233 return this->erase_cycles[sector];
234 }
235
get_total_erase_cycles()236 uint32_t SpiFlash::get_total_erase_cycles()
237 {
238 return this->total_erase_cycles;
239 }
240
set_erase_cycles_limit(uint32_t limit)241 void SpiFlash::set_erase_cycles_limit(uint32_t limit)
242 {
243 this->erase_cycles_limit = limit;
244 }
245
set_total_erase_cycles_limit(uint32_t limit)246 void SpiFlash::set_total_erase_cycles_limit(uint32_t limit)
247 {
248 this->total_erase_cycles_limit = limit;
249 }
250
reset_erase_cycles()251 void SpiFlash::reset_erase_cycles()
252 {
253 memset(this->erase_cycles, 0, sizeof(this->sectors * sizeof(uint32_t)));
254 }
255
reset_total_erase_cycles()256 void SpiFlash::reset_total_erase_cycles()
257 {
258 this->total_erase_cycles = 0;
259 }
260