1 /* 2 * Copyright (C) 2013 Henrik Nordstrom <henrik@henriknordstrom.net> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <config.h> 8 #include <common.h> 9 #include <part.h> 10 #include <os.h> 11 #include <malloc.h> 12 #include <sandboxblockdev.h> 13 #include <asm/errno.h> 14 15 static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES]; 16 17 static struct host_block_dev *find_host_device(int dev) 18 { 19 if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES) 20 return &host_devices[dev]; 21 22 return NULL; 23 } 24 25 static unsigned long host_block_read(struct blk_desc *block_dev, 26 unsigned long start, lbaint_t blkcnt, 27 void *buffer) 28 { 29 int dev = block_dev->devnum; 30 struct host_block_dev *host_dev = find_host_device(dev); 31 32 if (!host_dev) 33 return -1; 34 35 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == 36 -1) { 37 printf("ERROR: Invalid block %lx\n", start); 38 return -1; 39 } 40 ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz); 41 if (len >= 0) 42 return len / block_dev->blksz; 43 return -1; 44 } 45 46 static unsigned long host_block_write(struct blk_desc *block_dev, 47 unsigned long start, lbaint_t blkcnt, 48 const void *buffer) 49 { 50 int dev = block_dev->devnum; 51 struct host_block_dev *host_dev = find_host_device(dev); 52 53 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) == 54 -1) { 55 printf("ERROR: Invalid block %lx\n", start); 56 return -1; 57 } 58 ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz); 59 if (len >= 0) 60 return len / block_dev->blksz; 61 return -1; 62 } 63 64 int host_dev_bind(int dev, char *filename) 65 { 66 struct host_block_dev *host_dev = find_host_device(dev); 67 68 if (!host_dev) 69 return -1; 70 if (host_dev->blk_dev.priv) { 71 os_close(host_dev->fd); 72 host_dev->blk_dev.priv = NULL; 73 } 74 if (host_dev->filename) 75 free(host_dev->filename); 76 if (filename && *filename) { 77 host_dev->filename = strdup(filename); 78 } else { 79 host_dev->filename = NULL; 80 return 0; 81 } 82 83 host_dev->fd = os_open(host_dev->filename, OS_O_RDWR); 84 if (host_dev->fd == -1) { 85 printf("Failed to access host backing file '%s'\n", 86 host_dev->filename); 87 return 1; 88 } 89 90 struct blk_desc *blk_dev = &host_dev->blk_dev; 91 blk_dev->if_type = IF_TYPE_HOST; 92 blk_dev->priv = host_dev; 93 blk_dev->blksz = 512; 94 blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz; 95 blk_dev->block_read = host_block_read; 96 blk_dev->block_write = host_block_write; 97 blk_dev->devnum = dev; 98 blk_dev->part_type = PART_TYPE_UNKNOWN; 99 part_init(blk_dev); 100 101 return 0; 102 } 103 104 int host_get_dev_err(int devnum, struct blk_desc **blk_devp) 105 { 106 struct host_block_dev *host_dev = find_host_device(devnum); 107 108 if (!host_dev) 109 return -ENODEV; 110 111 if (!host_dev->blk_dev.priv) 112 return -ENOENT; 113 114 *blk_devp = &host_dev->blk_dev; 115 return 0; 116 } 117 118 struct blk_desc *host_get_dev(int dev) 119 { 120 struct blk_desc *blk_dev; 121 122 if (host_get_dev_err(dev, &blk_dev)) 123 return NULL; 124 125 return blk_dev; 126 } 127