blob: 5885fc358a54267202bc9252c3f04ae1cb49f86a [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;
27 int ret, fd, size;
28 char *fname;
29
30 if (!filename)
31 return -EINVAL;
32
33 if (plat->fd)
34 return log_msg_ret("fd", -EEXIST);
35
36 /* Sanity check that host_sb_bind() has been used */
37 ret = blk_find_from_parent(dev, &blk);
38 if (ret)
39 return ret;
40
41 fd = os_open(filename, OS_O_RDWR);
42 if (fd == -1) {
43 printf("Failed to access host backing file '%s', trying read-only\n",
44 filename);
45 fd = os_open(filename, OS_O_RDONLY);
46 if (fd == -1) {
47 printf("- still failed\n");
48 return log_msg_ret("open", -ENOENT);
49 }
50 }
51
52 fname = strdup(filename);
53 if (!fname) {
54 ret = -ENOMEM;
55 goto err_fname;
56 }
57
58 size = os_filesize(fd);
59 desc = dev_get_uclass_plat(blk);
60 desc->lba = size / desc->blksz;
61
62 /* write this in last, when nothing can go wrong */
63 plat = dev_get_plat(dev);
64 plat->fd = fd;
65 plat->filename = fname;
66
67 return 0;
68
69err_fname:
70 os_close(fd);
71
72 return ret;
73}
74
75int host_sb_detach_file(struct udevice *dev)
76{
77 struct host_sb_plat *plat = dev_get_plat(dev);
78 int ret;
79
80 if (!plat->fd)
81 return log_msg_ret("fd", -ENOENT);
82
83 ret = device_remove(dev, DM_REMOVE_NORMAL);
84 if (ret)
85 return log_msg_ret("rem", ret);
86
87 /* Unbind all children */
88 ret = device_chld_unbind(dev, NULL);
89 if (ret)
90 return log_msg_ret("unb", ret);
91
92 os_close(plat->fd);
93 plat->fd = 0;
94 free(plat->filename);
95 free(plat->label);
96
97 return 0;
98}
99
100static int host_sb_bind(struct udevice *dev)
101{
102 struct udevice *blk, *bdev;
103 struct blk_desc *desc;
104 int ret;
105
106 ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST,
107 dev_seq(dev), 512, 0, &blk);
108 if (ret)
109 return log_msg_ret("blk", ret);
110
111 desc = dev_get_uclass_plat(blk);
112 snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot");
113 snprintf(desc->product, BLK_PRD_SIZE, "hostfile");
114 snprintf(desc->revision, BLK_REV_SIZE, "1.0");
115
116 if (CONFIG_IS_ENABLED(BOOTSTD)) {
117 ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev);
118 if (ret)
119 return log_msg_ret("bd", ret);
120 }
121
122 return 0;
123}
124
125struct host_ops host_sb_ops = {
126 .attach_file = host_sb_attach_file,
127 .detach_file = host_sb_detach_file,
128};
129
130static const struct udevice_id host_ids[] = {
131 { .compatible = "sandbox,host" },
132 { }
133};
134
135U_BOOT_DRIVER(host_sb_drv) = {
136 .name = "host_sb_drv",
137 .id = UCLASS_HOST,
138 .of_match = host_ids,
139 .ops = &host_sb_ops,
140 .bind = host_sb_bind,
141 .plat_auto = sizeof(struct host_sb_plat),
142};