blob: 52313435a0cb84b3b2b3b699506d519db35995be [file] [log] [blame]
Simon Glass39f06b52022-10-29 19:47:16 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Driver for sandbox host interface, used to access files on the host which
4 * contain partitions and filesystem
5 *
6 * Copyright 2022 Google LLC
7 * Written by Simon Glass <sjg@chromium.org>
8 */
9
10#define LOG_CATEGORY UCLASS_HOST
11
12#include <common.h>
13#include <blk.h>
14#include <bootdev.h>
15#include <dm.h>
16#include <log.h>
17#include <malloc.h>
18#include <os.h>
19#include <sandbox_host.h>
20#include <dm/device-internal.h>
21
22static int host_sb_attach_file(struct udevice *dev, const char *filename)
23{
24 struct host_sb_plat *plat = dev_get_plat(dev);
25 struct blk_desc *desc;
26 struct udevice *blk;
Heinrich Schuchardt6db1b652023-04-05 11:34:15 +020027 int ret, fd;
28 off_t size;
Simon Glass39f06b52022-10-29 19:47:16 -060029 char *fname;
30
31 if (!filename)
32 return -EINVAL;
33
34 if (plat->fd)
35 return log_msg_ret("fd", -EEXIST);
36
37 /* Sanity check that host_sb_bind() has been used */
38 ret = blk_find_from_parent(dev, &blk);
39 if (ret)
40 return ret;
41
42 fd = os_open(filename, OS_O_RDWR);
43 if (fd == -1) {
44 printf("Failed to access host backing file '%s', trying read-only\n",
45 filename);
46 fd = os_open(filename, OS_O_RDONLY);
47 if (fd == -1) {
48 printf("- still failed\n");
49 return log_msg_ret("open", -ENOENT);
50 }
51 }
52
53 fname = strdup(filename);
54 if (!fname) {
55 ret = -ENOMEM;
56 goto err_fname;
57 }
58
59 size = os_filesize(fd);
60 desc = dev_get_uclass_plat(blk);
Bin Mengcc4c5312023-09-26 16:43:35 +080061 if (size % desc->blksz) {
62 printf("The size of host backing file '%s' is not multiple of "
63 "the device block size\n", filename);
Dan Carpentere96a04d2024-01-31 10:09:52 +030064 ret = -EINVAL;
Bin Mengcc4c5312023-09-26 16:43:35 +080065 goto err_fname;
66 }
Simon Glass39f06b52022-10-29 19:47:16 -060067 desc->lba = size / desc->blksz;
68
69 /* write this in last, when nothing can go wrong */
70 plat = dev_get_plat(dev);
71 plat->fd = fd;
72 plat->filename = fname;
73
74 return 0;
75
76err_fname:
77 os_close(fd);
78
79 return ret;
80}
81
Bin Meng371fb0e2023-09-26 16:43:34 +080082static int host_sb_detach_file(struct udevice *dev)
Simon Glass39f06b52022-10-29 19:47:16 -060083{
84 struct host_sb_plat *plat = dev_get_plat(dev);
85 int ret;
86
87 if (!plat->fd)
88 return log_msg_ret("fd", -ENOENT);
89
90 ret = device_remove(dev, DM_REMOVE_NORMAL);
91 if (ret)
92 return log_msg_ret("rem", ret);
93
94 /* Unbind all children */
95 ret = device_chld_unbind(dev, NULL);
96 if (ret)
97 return log_msg_ret("unb", ret);
98
99 os_close(plat->fd);
100 plat->fd = 0;
101 free(plat->filename);
102 free(plat->label);
103
104 return 0;
105}
106
107static int host_sb_bind(struct udevice *dev)
108{
109 struct udevice *blk, *bdev;
110 struct blk_desc *desc;
111 int ret;
112
113 ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
Bin Meng2294ecb2023-09-26 16:43:31 +0800114 dev_seq(dev), DEFAULT_BLKSZ, 0, &blk);
Simon Glass39f06b52022-10-29 19:47:16 -0600115 if (ret)
116 return log_msg_ret("blk", ret);
117
118 desc = dev_get_uclass_plat(blk);
119 snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
120 snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
121 snprintf(desc->revision, BLK_REV_SIZE, "1.0");
122
123 if (CONFIG_IS_ENABLED(BOOTSTD)) {
124 ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev);
125 if (ret)
126 return log_msg_ret("bd", ret);
127 }
128
129 return 0;
130}
131
Bin Meng371fb0e2023-09-26 16:43:34 +0800132static struct host_ops host_sb_ops = {
Simon Glass39f06b52022-10-29 19:47:16 -0600133 .attach_file = host_sb_attach_file,
134 .detach_file = host_sb_detach_file,
135};
136
137static const struct udevice_id host_ids[] = {
138 { .compatible = "sandbox,host" },
139 { }
140};
141
142U_BOOT_DRIVER(host_sb_drv) = {
143 .name = "host_sb_drv",
144 .id = UCLASS_HOST,
145 .of_match = host_ids,
146 .ops = &host_sb_ops,
147 .bind = host_sb_bind,
148 .plat_auto = sizeof(struct host_sb_plat),
149};