1// SPDX-License-Identifier: GPL-2.0 2/* 3 * 2017 by Marek Beh��n <kabel@kernel.org> 4 * 5 * Derived from code in ext4/dev.c, which was based on reiserfs/dev.c 6 */ 7 8#define LOG_CATEGORY LOGC_CORE 9 10#include <common.h> 11#include <blk.h> 12#include <compiler.h> 13#include <log.h> 14#include <part.h> 15#include <memalign.h> 16 17int fs_devread(struct blk_desc *blk, struct disk_partition *partition, 18 lbaint_t sector, int byte_offset, int byte_len, char *buf) 19{ 20 unsigned block_len; 21 int log2blksz; 22 ALLOC_CACHE_ALIGN_BUFFER(char, sec_buf, (blk ? blk->blksz : 0)); 23 if (blk == NULL) { 24 log_err("** Invalid Block Device Descriptor (NULL)\n"); 25 return 0; 26 } 27 log2blksz = blk->log2blksz; 28 29 /* Check partition boundaries */ 30 if ((sector + ((byte_offset + byte_len - 1) >> log2blksz)) 31 >= partition->size) { 32 log_debug("read outside partition " LBAFU "\n", sector); 33 return 0; 34 } 35 36 /* Get the read to the beginning of a partition */ 37 sector += byte_offset >> log2blksz; 38 byte_offset &= blk->blksz - 1; 39 40 log_debug(" <" LBAFU ", %d, %d>\n", sector, byte_offset, byte_len); 41 42 if (byte_offset != 0) { 43 int readlen; 44 /* read first part which isn't aligned with start of sector */ 45 if (blk_dread(blk, partition->start + sector, 1, 46 (void *)sec_buf) != 1) { 47 log_err(" ** %s read error **\n", __func__); 48 return 0; 49 } 50 readlen = min((int)blk->blksz - byte_offset, 51 byte_len); 52 memcpy(buf, sec_buf + byte_offset, readlen); 53 buf += readlen; 54 byte_len -= readlen; 55 sector++; 56 } 57 58 if (byte_len == 0) 59 return 1; 60 61 /* read sector aligned part */ 62 block_len = byte_len & ~(blk->blksz - 1); 63 64 if (block_len == 0) { 65 ALLOC_CACHE_ALIGN_BUFFER(u8, p, blk->blksz); 66 67 block_len = blk->blksz; 68 blk_dread(blk, partition->start + sector, 1, 69 (void *)p); 70 memcpy(buf, p, byte_len); 71 return 1; 72 } 73 74 if (blk_dread(blk, partition->start + sector, 75 block_len >> log2blksz, (void *)buf) != 76 block_len >> log2blksz) { 77 log_err(" ** %s read error - block\n", __func__); 78 return 0; 79 } 80 block_len = byte_len & ~(blk->blksz - 1); 81 buf += block_len; 82 byte_len -= block_len; 83 sector += block_len / blk->blksz; 84 85 if (byte_len != 0) { 86 /* read rest of data which are not in whole sector */ 87 if (blk_dread(blk, partition->start + sector, 1, 88 (void *)sec_buf) != 1) { 89 log_err("* %s read error - last part\n", __func__); 90 return 0; 91 } 92 memcpy(buf, sec_buf, byte_len); 93 } 94 return 1; 95} 96