blob: dde9d6845f713e7d26eb95ecf44623109b4f35ee [file] [log] [blame]
Henrik Nordströmf4d8de42013-11-10 10:26:56 -07001/*
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
15static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
16
17static 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
Simon Glass4101f682016-02-29 15:25:34 -070025static unsigned long host_block_read(struct blk_desc *block_dev,
Stephen Warren7c4213f2015-12-07 11:38:48 -070026 unsigned long start, lbaint_t blkcnt,
27 void *buffer)
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070028{
Simon Glassbcce53d2016-02-29 15:25:51 -070029 int dev = block_dev->devnum;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070030 struct host_block_dev *host_dev = find_host_device(dev);
31
32 if (!host_dev)
33 return -1;
Simon Glass7ded9592016-02-29 15:25:56 -070034
35 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
36 -1) {
37 printf("ERROR: Invalid block %lx\n", start);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070038 return -1;
39 }
Simon Glass7ded9592016-02-29 15:25:56 -070040 ssize_t len = os_read(host_dev->fd, buffer, blkcnt * block_dev->blksz);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070041 if (len >= 0)
Simon Glass7ded9592016-02-29 15:25:56 -070042 return len / block_dev->blksz;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070043 return -1;
44}
45
Simon Glass4101f682016-02-29 15:25:34 -070046static unsigned long host_block_write(struct blk_desc *block_dev,
Stephen Warren7c4213f2015-12-07 11:38:48 -070047 unsigned long start, lbaint_t blkcnt,
48 const void *buffer)
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070049{
Simon Glassbcce53d2016-02-29 15:25:51 -070050 int dev = block_dev->devnum;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070051 struct host_block_dev *host_dev = find_host_device(dev);
Simon Glass7ded9592016-02-29 15:25:56 -070052
53 if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
54 -1) {
55 printf("ERROR: Invalid block %lx\n", start);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070056 return -1;
57 }
Simon Glass7ded9592016-02-29 15:25:56 -070058 ssize_t len = os_write(host_dev->fd, buffer, blkcnt * block_dev->blksz);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070059 if (len >= 0)
Simon Glass7ded9592016-02-29 15:25:56 -070060 return len / block_dev->blksz;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070061 return -1;
62}
63
64int 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
Simon Glass4101f682016-02-29 15:25:34 -070090 struct blk_desc *blk_dev = &host_dev->blk_dev;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070091 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;
Simon Glassbcce53d2016-02-29 15:25:51 -070097 blk_dev->devnum = dev;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -070098 blk_dev->part_type = PART_TYPE_UNKNOWN;
Simon Glass3e8bd462016-02-29 15:25:48 -070099 part_init(blk_dev);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700100
101 return 0;
102}
103
Simon Glass7ded9592016-02-29 15:25:56 -0700104int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700105{
Simon Glass7ded9592016-02-29 15:25:56 -0700106 struct host_block_dev *host_dev = find_host_device(devnum);
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700107
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
Simon Glass4101f682016-02-29 15:25:34 -0700118struct blk_desc *host_get_dev(int dev)
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700119{
Simon Glass4101f682016-02-29 15:25:34 -0700120 struct blk_desc *blk_dev;
Henrik Nordströmf4d8de42013-11-10 10:26:56 -0700121
122 if (host_get_dev_err(dev, &blk_dev))
123 return NULL;
124
125 return blk_dev;
126}