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