Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: nRF51_Vdd TextLCD BME280
MBRBlockDevice.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2017 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "MBRBlockDevice.h" 00018 #include "platform/mbed_critical.h" 00019 #include "platform/mbed_toolchain.h" 00020 #include "platform/mbed_assert.h" 00021 #include <algorithm> 00022 #include <string.h> 00023 00024 // On disk structures, all entries are little endian 00025 MBED_PACKED(struct) mbr_entry { 00026 uint8_t status; 00027 uint8_t chs_start[3]; 00028 uint8_t type; 00029 uint8_t chs_stop[3]; 00030 uint32_t lba_offset; 00031 uint32_t lba_size; 00032 }; 00033 00034 MBED_PACKED(struct) mbr_table { 00035 struct mbr_entry entries[4]; 00036 uint8_t signature[2]; 00037 }; 00038 00039 // Little-endian conversion, should compile to noop 00040 // if system is little-endian 00041 static inline uint32_t tole32(uint32_t a) 00042 { 00043 union { 00044 uint32_t u32; 00045 uint8_t u8[4]; 00046 } w; 00047 00048 w.u8[0] = a >> 0; 00049 w.u8[1] = a >> 8; 00050 w.u8[2] = a >> 16; 00051 w.u8[3] = a >> 24; 00052 00053 return w.u32; 00054 } 00055 00056 static inline uint32_t fromle32(uint32_t a) 00057 { 00058 return tole32(a); 00059 } 00060 00061 static void tochs(uint32_t lba, uint8_t chs[3]) 00062 { 00063 uint32_t sector = std::min<uint32_t>(lba, 0xfffffd)+1; 00064 chs[0] = (sector >> 6) & 0xff; 00065 chs[1] = ((sector >> 0) & 0x3f) | ((sector >> 16) & 0xc0); 00066 chs[2] = (sector >> 14) & 0xff; 00067 } 00068 00069 00070 // Partition after address are turned into absolute 00071 // addresses, assumes bd is initialized 00072 static int partition_absolute( 00073 BlockDevice *bd, int part, uint8_t type, 00074 bd_size_t offset, bd_size_t size) 00075 { 00076 // Allocate smallest buffer necessary to write MBR 00077 uint32_t buffer_size = std::max<uint32_t>(bd->get_program_size(), sizeof(struct mbr_table)); 00078 00079 // Prevent alignment issues 00080 if(buffer_size % bd->get_program_size() != 0) { 00081 buffer_size += bd->get_program_size() - (buffer_size % bd->get_program_size()); 00082 } 00083 00084 uint8_t *buffer = new uint8_t[buffer_size]; 00085 00086 // Check for existing MBR 00087 int err = bd->read(buffer, 512-buffer_size, buffer_size); 00088 if (err) { 00089 delete[] buffer; 00090 return err; 00091 } 00092 00093 struct mbr_table *table = reinterpret_cast<struct mbr_table*>( 00094 &buffer[buffer_size - sizeof(struct mbr_table)]); 00095 if (table->signature[0] != 0x55 || table->signature[1] != 0xaa) { 00096 // Setup default values for MBR 00097 table->signature[0] = 0x55; 00098 table->signature[1] = 0xaa; 00099 memset(table->entries, 0, sizeof(table->entries)); 00100 } 00101 00102 // For Windows-formatted SD card, it is not partitioned (no MBR), but its PBR has the 00103 // same boot signature (0xaa55) as MBR. We would easily mis-recognize this SD card has valid 00104 // partitions if we only check partition type. We add check by only accepting 0x00 (inactive) 00105 // /0x80 (active) for valid partition status. 00106 for (int i = 1; i <= 4; i++) { 00107 if (table->entries[i-1].status != 0x00 && 00108 table->entries[i-1].status != 0x80) { 00109 memset(table->entries, 0, sizeof(table->entries)); 00110 break; 00111 } 00112 } 00113 00114 // Setup new partition 00115 MBED_ASSERT(part >= 1 && part <= 4); 00116 table->entries[part-1].status = 0x00; // inactive (not bootable) 00117 table->entries[part-1].type = type; 00118 00119 // lba dimensions 00120 MBED_ASSERT(bd->is_valid_erase(offset, size)); 00121 uint32_t sector = std::max<uint32_t>(bd->get_erase_size(), 512); 00122 uint32_t lba_offset = offset / sector; 00123 uint32_t lba_size = size / sector; 00124 table->entries[part-1].lba_offset = tole32(lba_offset); 00125 table->entries[part-1].lba_size = tole32(lba_size); 00126 00127 // chs dimensions 00128 tochs(lba_offset, table->entries[part-1].chs_start); 00129 tochs(lba_offset+lba_size-1, table->entries[part-1].chs_stop); 00130 00131 // Check that we don't overlap other entries 00132 for (int i = 1; i <= 4; i++) { 00133 if (i != part && table->entries[i-1].type != 0x00) { 00134 uint32_t neighbor_lba_offset = fromle32(table->entries[i-1].lba_offset); 00135 uint32_t neighbor_lba_size = fromle32(table->entries[i-1].lba_size); 00136 MBED_ASSERT( 00137 (lba_offset >= neighbor_lba_offset + neighbor_lba_size) || 00138 (lba_offset + lba_size <= neighbor_lba_offset)); 00139 (void)neighbor_lba_offset; 00140 (void)neighbor_lba_size; 00141 } 00142 } 00143 00144 // Write out MBR 00145 err = bd->erase(0, bd->get_erase_size()); 00146 if (err) { 00147 delete[] buffer; 00148 return err; 00149 } 00150 00151 err = bd->program(buffer, 512-buffer_size, buffer_size); 00152 delete[] buffer; 00153 return err; 00154 } 00155 00156 int MBRBlockDevice::partition(BlockDevice *bd, int part, uint8_t type, bd_addr_t start) 00157 { 00158 int err = bd->init(); 00159 if (err) { 00160 return err; 00161 } 00162 00163 // Calculate dimensions 00164 bd_size_t offset = ((int64_t)start < 0) ? -start : start; 00165 bd_size_t size = bd->size(); 00166 00167 if (offset < 512) { 00168 offset += std::max<uint32_t>(bd->get_erase_size(), 512); 00169 } 00170 00171 size -= offset; 00172 00173 err = partition_absolute(bd, part, type, offset, size); 00174 if (err) { 00175 return err; 00176 } 00177 00178 err = bd->deinit(); 00179 if (err) { 00180 return err; 00181 } 00182 00183 return 0; 00184 } 00185 00186 int MBRBlockDevice::partition(BlockDevice *bd, int part, uint8_t type, 00187 bd_addr_t start, bd_addr_t stop) 00188 { 00189 int err = bd->init(); 00190 if (err) { 00191 return err; 00192 } 00193 00194 // Calculate dimensions 00195 bd_size_t offset = ((int64_t)start < 0) ? -start : start; 00196 bd_size_t size = ((int64_t)stop < 0) ? -stop : stop; 00197 00198 if (offset < 512) { 00199 offset += std::max<uint32_t>(bd->get_erase_size(), 512); 00200 } 00201 00202 size -= offset; 00203 00204 err = partition_absolute(bd, part, type, offset, size); 00205 if (err) { 00206 return err; 00207 } 00208 00209 err = bd->deinit(); 00210 if (err) { 00211 return err; 00212 } 00213 00214 return 0; 00215 } 00216 00217 MBRBlockDevice::MBRBlockDevice(BlockDevice *bd, int part) 00218 : _bd(bd), _offset(0), _size(0), _type(0), _part(part), _init_ref_count(0), _is_initialized(false) 00219 { 00220 MBED_ASSERT(_part >= 1 && _part <= 4); 00221 } 00222 00223 int MBRBlockDevice::init() 00224 { 00225 uint32_t buffer_size; 00226 uint8_t *buffer = 0; 00227 struct mbr_table *table; 00228 bd_size_t sector; 00229 int err; 00230 00231 uint32_t val = core_util_atomic_incr_u32(&_init_ref_count, 1); 00232 00233 if (val != 1) { 00234 return BD_ERROR_OK; 00235 } 00236 00237 err = _bd->init(); 00238 if (err) { 00239 goto fail; 00240 } 00241 00242 // Allocate smallest buffer necessary to write MBR 00243 buffer_size = std::max<uint32_t>(_bd->get_read_size(), sizeof(struct mbr_table)); 00244 buffer = new uint8_t[buffer_size]; 00245 00246 err = _bd->read(buffer, 512-buffer_size, buffer_size); 00247 if (err) { 00248 goto fail; 00249 } 00250 00251 // Check for valid table 00252 table = reinterpret_cast<struct mbr_table*>(&buffer[buffer_size - sizeof(struct mbr_table)]); 00253 if (table->signature[0] != 0x55 || table->signature[1] != 0xaa) { 00254 err = BD_ERROR_INVALID_MBR; 00255 goto fail; 00256 } 00257 00258 // Check for valid partition status 00259 // Same reason as in partition_absolute regarding Windows-formatted SD card 00260 if (table->entries[_part-1].status != 0x00 && 00261 table->entries[_part-1].status != 0x80) { 00262 err = BD_ERROR_INVALID_PARTITION; 00263 goto fail; 00264 } 00265 00266 // Check for valid entry 00267 // 0x00 = no entry 00268 // 0x05, 0x0f = extended partitions, currently not supported 00269 if ((table->entries[_part-1].type == 0x00 || 00270 table->entries[_part-1].type == 0x05 || 00271 table->entries[_part-1].type == 0x0f)) { 00272 err = BD_ERROR_INVALID_PARTITION; 00273 goto fail; 00274 } 00275 00276 // Get partition attributes 00277 sector = std::max<uint32_t>(_bd->get_erase_size(), 512); 00278 _type = table->entries[_part-1].type; 00279 _offset = fromle32(table->entries[_part-1].lba_offset) * sector; 00280 _size = fromle32(table->entries[_part-1].lba_size) * sector; 00281 00282 // Check that block addresses are valid 00283 if (!_bd->is_valid_erase(_offset, _size)) { 00284 err = BD_ERROR_INVALID_PARTITION; 00285 goto fail; 00286 } 00287 00288 _is_initialized = true; 00289 delete[] buffer; 00290 return BD_ERROR_OK; 00291 00292 fail: 00293 delete[] buffer; 00294 _is_initialized = false; 00295 _init_ref_count = 0; 00296 return err; 00297 } 00298 00299 int MBRBlockDevice::deinit() 00300 { 00301 if (!_is_initialized) { 00302 return BD_ERROR_OK; 00303 } 00304 00305 uint32_t val = core_util_atomic_decr_u32(&_init_ref_count, 1); 00306 00307 if (val) { 00308 return BD_ERROR_OK; 00309 } 00310 00311 _is_initialized = false; 00312 return _bd->deinit(); 00313 } 00314 00315 int MBRBlockDevice::sync() 00316 { 00317 if (!_is_initialized) { 00318 return BD_ERROR_DEVICE_ERROR; 00319 } 00320 00321 return _bd->sync(); 00322 } 00323 00324 int MBRBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00325 { 00326 MBED_ASSERT(is_valid_read(addr, size)); 00327 if (!_is_initialized) { 00328 return BD_ERROR_DEVICE_ERROR; 00329 } 00330 00331 return _bd->read(b, addr + _offset, size); 00332 } 00333 00334 int MBRBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00335 { 00336 MBED_ASSERT(is_valid_program(addr, size)); 00337 if (!_is_initialized) { 00338 return BD_ERROR_DEVICE_ERROR; 00339 } 00340 00341 return _bd->program(b, addr + _offset, size); 00342 } 00343 00344 int MBRBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00345 { 00346 MBED_ASSERT(is_valid_erase(addr, size)); 00347 if (!_is_initialized) { 00348 return BD_ERROR_DEVICE_ERROR; 00349 } 00350 00351 return _bd->erase(addr + _offset, size); 00352 } 00353 00354 bd_size_t MBRBlockDevice::get_read_size() const 00355 { 00356 if (!_is_initialized) { 00357 return 0; 00358 } 00359 00360 return _bd->get_read_size(); 00361 } 00362 00363 bd_size_t MBRBlockDevice::get_program_size() const 00364 { 00365 if (!_is_initialized) { 00366 return 0; 00367 } 00368 00369 return _bd->get_program_size(); 00370 } 00371 00372 bd_size_t MBRBlockDevice::get_erase_size() const 00373 { 00374 if (!_is_initialized) { 00375 return 0; 00376 } 00377 00378 return _bd->get_erase_size(); 00379 } 00380 00381 bd_size_t MBRBlockDevice::get_erase_size(bd_addr_t addr) const 00382 { 00383 if (!_is_initialized) { 00384 return 0; 00385 } 00386 00387 return _bd->get_erase_size(_offset + addr); 00388 } 00389 00390 int MBRBlockDevice::get_erase_value() const 00391 { 00392 if (!_is_initialized) { 00393 return 0; 00394 } 00395 00396 return _bd->get_erase_value(); 00397 } 00398 00399 bd_size_t MBRBlockDevice::size() const 00400 { 00401 return _size; 00402 } 00403 00404 bd_size_t MBRBlockDevice::get_partition_start() const 00405 { 00406 return _offset; 00407 } 00408 00409 bd_size_t MBRBlockDevice::get_partition_stop() const 00410 { 00411 return _offset+_size; 00412 } 00413 00414 uint8_t MBRBlockDevice::get_partition_type() const 00415 { 00416 return _type; 00417 } 00418 00419 int MBRBlockDevice::get_partition_number() const 00420 { 00421 return _part; 00422 }
Generated on Tue Jul 12 2022 15:15:52 by
