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; 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 log2blksz = blk->log2blksz; 25 26 /* Check partition boundaries */ 27 if ((sector + ((byte_offset + byte_len - 1) >> log2blksz)) 28 >= partition->size) { 29 printf("%s read outside partition " LBAFU "\n", __func__, 30 sector); 31 return 0; 32 } 33 34 /* Get the read to the beginning of a partition */ 35 sector += byte_offset >> log2blksz; 36 byte_offset &= blk->blksz - 1; 37 38 debug(" <" LBAFU ", %d, %d>\n", sector, byte_offset, byte_len); 39 40 if (byte_offset != 0) { 41 int readlen; 42 /* read first part which isn't aligned with start of sector */ 43 if (blk_dread(blk, partition->start + sector, 1, 44 (void *)sec_buf) != 1) { 45 printf(" ** %s read error **\n", __func__); 46 return 0; 47 } 48 readlen = min((int)blk->blksz - byte_offset, 49 byte_len); 50 memcpy(buf, sec_buf + byte_offset, readlen); 51 buf += readlen; 52 byte_len -= readlen; 53 sector++; 54 } 55 56 if (byte_len == 0) 57 return 1; 58 59 /* read sector aligned part */ 60 block_len = byte_len & ~(blk->blksz - 1); 61 62 if (block_len == 0) { 63 ALLOC_CACHE_ALIGN_BUFFER(u8, p, blk->blksz); 64 65 block_len = blk->blksz; 66 blk_dread(blk, partition->start + sector, 1, 67 (void *)p); 68 memcpy(buf, p, byte_len); 69 return 1; 70 } 71 72 if (blk_dread(blk, partition->start + sector, 73 block_len >> log2blksz, (void *)buf) != 74 block_len >> log2blksz) { 75 printf(" ** %s read error - block\n", __func__); 76 return 0; 77 } 78 block_len = byte_len & ~(blk->blksz - 1); 79 buf += block_len; 80 byte_len -= block_len; 81 sector += block_len / blk->blksz; 82 83 if (byte_len != 0) { 84 /* read rest of data which are not in whole sector */ 85 if (blk_dread(blk, partition->start + sector, 1, 86 (void *)sec_buf) != 1) { 87 printf("* %s read error - last part\n", __func__); 88 return 0; 89 } 90 memcpy(buf, sec_buf, byte_len); 91 } 92 return 1; 93 } 94