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