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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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_atomic.h" 00019 #include "platform/mbed_toolchain.h" 00020 #include "platform/mbed_assert.h" 00021 #include <algorithm> 00022 #include <string.h> 00023 00024 namespace mbed { 00025 00026 // On disk structures, all entries are little endian 00027 MBED_PACKED(struct) mbr_entry { 00028 uint8_t status; 00029 uint8_t chs_start[3]; 00030 uint8_t type; 00031 uint8_t chs_stop[3]; 00032 uint32_t lba_offset; 00033 uint32_t lba_size; 00034 }; 00035 00036 MBED_PACKED(struct) mbr_table { 00037 struct mbr_entry entries[4]; 00038 uint8_t signature[2]; 00039 }; 00040 00041 // Little-endian conversion, should compile to noop 00042 // if system is little-endian 00043 static inline uint32_t tole32(uint32_t a) 00044 { 00045 union { 00046 uint32_t u32; 00047 uint8_t u8[4]; 00048 } w; 00049 00050 w.u8[0] = a >> 0; 00051 w.u8[1] = a >> 8; 00052 w.u8[2] = a >> 16; 00053 w.u8[3] = a >> 24; 00054 00055 return w.u32; 00056 } 00057 00058 static inline uint32_t fromle32(uint32_t a) 00059 { 00060 return tole32(a); 00061 } 00062 00063 static void tochs(uint32_t lba, uint8_t chs[3]) 00064 { 00065 uint32_t sector = std::min<uint32_t>(lba, 0xfffffd) + 1; 00066 chs[0] = (sector >> 6) & 0xff; 00067 chs[1] = ((sector >> 0) & 0x3f) | ((sector >> 16) & 0xc0); 00068 chs[2] = (sector >> 14) & 0xff; 00069 } 00070 00071 00072 // Partition after address are turned into absolute 00073 // addresses, assumes bd is initialized 00074 static int partition_absolute( 00075 BlockDevice *bd, int part, uint8_t type, 00076 bd_size_t offset, bd_size_t size) 00077 { 00078 // Allocate smallest buffer necessary to write MBR 00079 uint32_t buffer_size = std::max<uint32_t>(bd->get_program_size(), sizeof(struct mbr_table)); 00080 00081 // Prevent alignment issues 00082 if (buffer_size % bd->get_program_size() != 0) { 00083 buffer_size += bd->get_program_size() - (buffer_size % bd->get_program_size()); 00084 } 00085 00086 uint8_t *buffer = new uint8_t[buffer_size]; 00087 00088 // Check for existing MBR 00089 int err = bd->read(buffer, 512 - buffer_size, buffer_size); 00090 if (err) { 00091 delete[] buffer; 00092 return err; 00093 } 00094 00095 uint32_t table_start_offset = buffer_size - sizeof(struct mbr_table); 00096 struct mbr_table *table = reinterpret_cast<struct mbr_table *>( 00097 &buffer[table_start_offset]); 00098 if (table->signature[0] != 0x55 || table->signature[1] != 0xaa) { 00099 // Setup default values for MBR 00100 table->signature[0] = 0x55; 00101 table->signature[1] = 0xaa; 00102 memset(table->entries, 0, sizeof(table->entries)); 00103 } 00104 00105 // For Windows-formatted SD card, it is not partitioned (no MBR), but its PBR has the 00106 // same boot signature (0xaa55) as MBR. We would easily mis-recognize this SD card has valid 00107 // partitions if we only check partition type. We add check by only accepting 0x00 (inactive) 00108 // /0x80 (active) for valid partition status. 00109 for (int i = 1; i <= 4; i++) { 00110 if (table->entries[i - 1].status != 0x00 && 00111 table->entries[i - 1].status != 0x80) { 00112 memset(table->entries, 0, sizeof(table->entries)); 00113 break; 00114 } 00115 } 00116 00117 // Setup new partition 00118 MBED_ASSERT(part >= 1 && part <= 4); 00119 table->entries[part - 1].status = 0x00; // inactive (not bootable) 00120 table->entries[part - 1].type = type; 00121 00122 // lba dimensions 00123 MBED_ASSERT(bd->is_valid_erase(offset, size)); 00124 uint32_t sector = std::max<uint32_t>(bd->get_erase_size(), 512); 00125 uint32_t lba_offset = offset / sector; 00126 uint32_t lba_size = size / sector; 00127 table->entries[part - 1].lba_offset = tole32(lba_offset); 00128 table->entries[part - 1].lba_size = tole32(lba_size); 00129 00130 // chs dimensions 00131 tochs(lba_offset, table->entries[part - 1].chs_start); 00132 tochs(lba_offset + lba_size - 1, table->entries[part - 1].chs_stop); 00133 00134 // Check that we don't overlap other entries 00135 for (int i = 1; i <= 4; i++) { 00136 if (i != part && table->entries[i - 1].type != 0x00) { 00137 uint32_t neighbor_lba_offset = fromle32(table->entries[i - 1].lba_offset); 00138 uint32_t neighbor_lba_size = fromle32(table->entries[i - 1].lba_size); 00139 MBED_ASSERT( 00140 (lba_offset >= neighbor_lba_offset + neighbor_lba_size) || 00141 (lba_offset + lba_size <= neighbor_lba_offset)); 00142 (void)neighbor_lba_offset; 00143 (void)neighbor_lba_size; 00144 } 00145 } 00146 00147 // As the erase operation may do nothing, erase remainder of the buffer, to eradicate 00148 // any remaining programmed data (such as previously programmed file systems). 00149 if (table_start_offset > 0) { 00150 memset(buffer, 0xFF, table_start_offset); 00151 } 00152 if (table_start_offset + sizeof(struct mbr_table) < buffer_size) { 00153 memset(buffer + table_start_offset + sizeof(struct mbr_table), 0xFF, 00154 buffer_size - (table_start_offset + sizeof(struct mbr_table))); 00155 } 00156 00157 // Write out MBR 00158 err = bd->erase(0, bd->get_erase_size()); 00159 if (err) { 00160 delete[] buffer; 00161 return err; 00162 } 00163 00164 err = bd->program(buffer, 512 - buffer_size, buffer_size); 00165 delete[] buffer; 00166 return err; 00167 } 00168 00169 int MBRBlockDevice::partition(BlockDevice *bd, int part, uint8_t type, bd_addr_t start) 00170 { 00171 int err = bd->init(); 00172 if (err) { 00173 return err; 00174 } 00175 00176 // Calculate dimensions 00177 bd_size_t offset = ((int64_t)start < 0) ? -start : start; 00178 bd_size_t size = bd->size(); 00179 00180 if (offset < 512) { 00181 offset += std::max<uint32_t>(bd->get_erase_size(), 512); 00182 } 00183 00184 size -= offset; 00185 00186 err = partition_absolute(bd, part, type, offset, size); 00187 if (err) { 00188 return err; 00189 } 00190 00191 err = bd->deinit(); 00192 if (err) { 00193 return err; 00194 } 00195 00196 return 0; 00197 } 00198 00199 int MBRBlockDevice::partition(BlockDevice *bd, int part, uint8_t type, 00200 bd_addr_t start, bd_addr_t stop) 00201 { 00202 int err = bd->init(); 00203 if (err) { 00204 return err; 00205 } 00206 00207 // Calculate dimensions 00208 bd_size_t offset = ((int64_t)start < 0) ? -start : start; 00209 bd_size_t size = ((int64_t)stop < 0) ? -stop : stop; 00210 00211 if (offset < 512) { 00212 offset += std::max<uint32_t>(bd->get_erase_size(), 512); 00213 } 00214 00215 size -= offset; 00216 00217 err = partition_absolute(bd, part, type, offset, size); 00218 if (err) { 00219 return err; 00220 } 00221 00222 err = bd->deinit(); 00223 if (err) { 00224 return err; 00225 } 00226 00227 return 0; 00228 } 00229 00230 MBRBlockDevice::MBRBlockDevice(BlockDevice *bd, int part) 00231 : _bd(bd), _offset(0), _size(0), _type(0), _part(part), _init_ref_count(0), _is_initialized(false) 00232 { 00233 MBED_ASSERT(_part >= 1 && _part <= 4); 00234 } 00235 00236 int MBRBlockDevice::init() 00237 { 00238 uint32_t buffer_size; 00239 uint8_t *buffer = 0; 00240 struct mbr_table *table; 00241 bd_size_t sector; 00242 int err; 00243 00244 uint32_t val = core_util_atomic_incr_u32 (&_init_ref_count, 1); 00245 00246 if (val != 1) { 00247 return BD_ERROR_OK; 00248 } 00249 00250 err = _bd->init(); 00251 if (err) { 00252 goto fail; 00253 } 00254 00255 // Allocate smallest buffer necessary to write MBR 00256 buffer_size = std::max<uint32_t>(_bd->get_read_size(), sizeof(struct mbr_table)); 00257 buffer = new uint8_t[buffer_size]; 00258 00259 err = _bd->read(buffer, 512 - buffer_size, buffer_size); 00260 if (err) { 00261 goto fail; 00262 } 00263 00264 // Check for valid table 00265 table = reinterpret_cast<struct mbr_table *>(&buffer[buffer_size - sizeof(struct mbr_table)]); 00266 if (table->signature[0] != 0x55 || table->signature[1] != 0xaa) { 00267 err = BD_ERROR_INVALID_MBR; 00268 goto fail; 00269 } 00270 00271 // Check for valid partition status 00272 // Same reason as in partition_absolute regarding Windows-formatted SD card 00273 if (table->entries[_part - 1].status != 0x00 && 00274 table->entries[_part - 1].status != 0x80) { 00275 err = BD_ERROR_INVALID_PARTITION; 00276 goto fail; 00277 } 00278 00279 // Check for valid entry 00280 // 0x00 = no entry 00281 // 0x05, 0x0f = extended partitions, currently not supported 00282 if ((table->entries[_part - 1].type == 0x00 || 00283 table->entries[_part - 1].type == 0x05 || 00284 table->entries[_part - 1].type == 0x0f)) { 00285 err = BD_ERROR_INVALID_PARTITION; 00286 goto fail; 00287 } 00288 00289 // Get partition attributes 00290 sector = std::max<uint32_t>(_bd->get_erase_size(), 512); 00291 _type = table->entries[_part - 1].type; 00292 _offset = fromle32(table->entries[_part - 1].lba_offset) * sector; 00293 _size = fromle32(table->entries[_part - 1].lba_size) * sector; 00294 00295 // Check that block addresses are valid 00296 if (!_bd->is_valid_erase(_offset, _size)) { 00297 err = BD_ERROR_INVALID_PARTITION; 00298 goto fail; 00299 } 00300 00301 _is_initialized = true; 00302 delete[] buffer; 00303 return BD_ERROR_OK; 00304 00305 fail: 00306 delete[] buffer; 00307 _is_initialized = false; 00308 _init_ref_count = 0; 00309 return err; 00310 } 00311 00312 int MBRBlockDevice::deinit() 00313 { 00314 if (!_is_initialized) { 00315 return BD_ERROR_OK; 00316 } 00317 00318 uint32_t val = core_util_atomic_decr_u32 (&_init_ref_count, 1); 00319 00320 if (val) { 00321 return BD_ERROR_OK; 00322 } 00323 00324 _is_initialized = false; 00325 return _bd->deinit(); 00326 } 00327 00328 int MBRBlockDevice::sync() 00329 { 00330 if (!_is_initialized) { 00331 return BD_ERROR_DEVICE_ERROR; 00332 } 00333 00334 return _bd->sync(); 00335 } 00336 00337 int MBRBlockDevice::read(void *b, bd_addr_t addr, bd_size_t size) 00338 { 00339 MBED_ASSERT(is_valid_read(addr, size)); 00340 if (!_is_initialized) { 00341 return BD_ERROR_DEVICE_ERROR; 00342 } 00343 00344 return _bd->read(b, addr + _offset, size); 00345 } 00346 00347 int MBRBlockDevice::program(const void *b, bd_addr_t addr, bd_size_t size) 00348 { 00349 MBED_ASSERT(is_valid_program(addr, size)); 00350 if (!_is_initialized) { 00351 return BD_ERROR_DEVICE_ERROR; 00352 } 00353 00354 return _bd->program(b, addr + _offset, size); 00355 } 00356 00357 int MBRBlockDevice::erase(bd_addr_t addr, bd_size_t size) 00358 { 00359 MBED_ASSERT(is_valid_erase(addr, size)); 00360 if (!_is_initialized) { 00361 return BD_ERROR_DEVICE_ERROR; 00362 } 00363 00364 return _bd->erase(addr + _offset, size); 00365 } 00366 00367 bd_size_t MBRBlockDevice::get_read_size() const 00368 { 00369 if (!_is_initialized) { 00370 return 0; 00371 } 00372 00373 return _bd->get_read_size(); 00374 } 00375 00376 bd_size_t MBRBlockDevice::get_program_size() const 00377 { 00378 if (!_is_initialized) { 00379 return 0; 00380 } 00381 00382 return _bd->get_program_size(); 00383 } 00384 00385 bd_size_t MBRBlockDevice::get_erase_size() const 00386 { 00387 if (!_is_initialized) { 00388 return 0; 00389 } 00390 00391 return _bd->get_erase_size(); 00392 } 00393 00394 bd_size_t MBRBlockDevice::get_erase_size(bd_addr_t addr) const 00395 { 00396 if (!_is_initialized) { 00397 return 0; 00398 } 00399 00400 return _bd->get_erase_size(_offset + addr); 00401 } 00402 00403 int MBRBlockDevice::get_erase_value() const 00404 { 00405 if (!_is_initialized) { 00406 return 0; 00407 } 00408 00409 return _bd->get_erase_value(); 00410 } 00411 00412 bd_size_t MBRBlockDevice::size() const 00413 { 00414 return _size; 00415 } 00416 00417 bd_size_t MBRBlockDevice::get_partition_start() const 00418 { 00419 return _offset; 00420 } 00421 00422 bd_size_t MBRBlockDevice::get_partition_stop() const 00423 { 00424 return _offset + _size; 00425 } 00426 00427 uint8_t MBRBlockDevice::get_partition_type() const 00428 { 00429 return _type; 00430 } 00431 00432 int MBRBlockDevice::get_partition_number() const 00433 { 00434 return _part; 00435 } 00436 00437 const char *MBRBlockDevice::get_type() const 00438 { 00439 if (_bd != NULL) { 00440 return _bd->get_type(); 00441 } 00442 00443 return NULL; 00444 } 00445 00446 } // namespace mbed 00447
Generated on Tue Jul 12 2022 13:54:34 by
