Coverage Report

Created: 2026-10-17 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/barebox/arch/sandbox/board/hostfile.c
Line
Count
Source
1
/*
2
 * hostfile.c - use files from the host to simalute barebox devices
3
 *
4
 * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
5
 *
6
 * This program is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License version 2
8
 * as published by the Free Software Foundation.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 */
16
17
#include <common.h>
18
#include <driver.h>
19
#include <block.h>
20
#include <disks.h>
21
#include <malloc.h>
22
#include <mach/linux.h>
23
#include <init.h>
24
#include <envfs.h>
25
#include <errno.h>
26
#include <linux/err.h>
27
#include <mach/hostfile.h>
28
#include <featctrl.h>
29
#include <xfuncs.h>
30
31
struct hf_priv {
32
  union {
33
    struct block_device blk;
34
    struct cdev cdev;
35
  };
36
  const char *filename;
37
  int fd;
38
  struct feature_controller feat;
39
};
40
41
static ssize_t hf_read(struct hf_priv *priv, void *buf, size_t count, loff_t offset, ulong flags)
42
234
{
43
234
  int fd = priv->fd;
44
45
234
  if (linux_lseek(fd, offset) != offset)
46
0
    return -EINVAL;
47
48
234
  return linux_read(fd, buf, count);
49
234
}
50
51
static ssize_t hf_write(struct hf_priv *priv, const void *buf, size_t count, loff_t offset, ulong flags)
52
26
{
53
26
  int fd = priv->fd;
54
55
26
  if (linux_lseek(fd, offset) != offset)
56
0
    return -EINVAL;
57
58
26
  return linux_write(fd, buf, count);
59
26
}
60
61
static ssize_t hf_cdev_read(struct cdev *cdev, void *buf, size_t count, loff_t offset, ulong flags)
62
234
{
63
234
  return hf_read(cdev->priv, buf, count, offset, flags);
64
234
}
65
66
static ssize_t hf_cdev_write(struct cdev *cdev, const void *buf, size_t count, loff_t offset, ulong flags)
67
26
{
68
26
  return hf_write(cdev->priv, buf, count, offset, flags);
69
26
}
70
71
static struct cdev_operations hf_cdev_ops = {
72
  .read  = hf_cdev_read,
73
  .write = hf_cdev_write,
74
};
75
76
static int hf_blk_read(struct block_device *blk, void *buf, sector_t block, blkcnt_t num_blocks)
77
0
{
78
0
  ssize_t ret = hf_read(container_of(blk, struct hf_priv, blk), buf,
79
0
            num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
80
0
  return ret > 0 ? 0 : ret;
81
0
}
82
83
static int hf_blk_write(struct block_device *blk, const void *buf, sector_t block, blkcnt_t num_blocks)
84
0
{
85
0
  ssize_t ret = hf_write(container_of(blk, struct hf_priv, blk), buf,
86
0
             num_blocks << SECTOR_SHIFT, block << SECTOR_SHIFT, 0);
87
0
  return ret > 0 ? 0 : ret;
88
0
}
89
90
static struct block_device_ops hf_blk_ops = {
91
  .read  = hf_blk_read,
92
  .write = hf_blk_write,
93
};
94
95
static void hf_info(struct device *dev)
96
0
{
97
0
  struct hf_priv *priv = dev->priv;
98
99
0
  printf("file: %s\n", priv->filename);
100
0
}
101
102
static int hostfile_feat_check(struct feature_controller *feat, int idx)
103
26
{
104
26
  struct hf_priv *priv = container_of(feat, struct hf_priv, feat);
105
106
26
  return priv->fd >= 0 ? FEATCTRL_OKAY : FEATCTRL_GATED;
107
26
}
108
109
static int hf_probe(struct device *dev)
110
26
{
111
26
  struct device_node *np = dev->of_node;
112
26
  struct hf_priv *priv = xzalloc(sizeof(*priv));
113
26
  struct cdev *cdev;
114
26
  bool is_featctrl = false, is_blockdev;
115
26
  u64 reg[2];
116
26
  int err;
117
118
26
  if (!np)
119
0
    return -ENODEV;
120
121
26
  dev->priv = priv;
122
26
  priv->fd = -1;
123
124
26
  if (IS_ENABLED(CONFIG_FEATURE_CONTROLLER) &&
125
26
      of_property_read_bool(np, "barebox,feature-controller")) {
126
26
    priv->feat.dev = dev;
127
26
    priv->feat.check = hostfile_feat_check;
128
129
26
    err = feature_controller_register(&priv->feat);
130
26
    if (err)
131
0
      return err;
132
133
26
    is_featctrl = true;
134
26
  }
135
136
137
26
  err = of_property_read_u64_array(np, "reg", reg, ARRAY_SIZE(reg));
138
26
  if (err)
139
0
    return err;
140
141
26
  of_property_read_u32(np, "barebox,fd", &priv->fd);
142
143
26
  err = of_property_read_string(np, "barebox,filename",
144
26
              &priv->filename);
145
26
  if (err)
146
0
    return err;
147
148
26
  if (priv->fd < 0)
149
0
    return is_featctrl ? 0 : priv->fd;
150
151
26
  devinfo_add(dev, hf_info);
152
153
26
  is_blockdev = of_property_read_bool(np, "barebox,blockdev");
154
155
26
  cdev = is_blockdev ? &priv->blk.cdev : &priv->cdev;
156
157
26
  cdev_set_of_node(cdev, np);
158
159
26
  if (is_blockdev) {
160
0
    cdev->name = strdup(np->name);
161
0
    priv->blk.dev = dev;
162
0
    priv->blk.ops = &hf_blk_ops;
163
0
    priv->blk.blockbits = SECTOR_SHIFT;
164
0
    priv->blk.num_blocks = reg[1] / SECTOR_SIZE;
165
0
    priv->blk.type = BLK_TYPE_VIRTUAL;
166
167
0
    err = blockdevice_register(&priv->blk);
168
0
    if (err)
169
0
      return err;
170
171
0
    dev_info(dev, "registered as block device\n");
172
26
  } else {
173
26
    cdev->name = strdup(np->name);
174
26
    cdev->dev = dev;
175
26
    cdev->ops = &hf_cdev_ops;
176
26
    cdev->size = reg[1];
177
26
    cdev->priv = priv;
178
179
26
    err = devfs_create(cdev);
180
26
    if (err)
181
0
      return err;
182
183
26
    dev_info(dev, "registered as character device\n");
184
26
  }
185
186
26
  of_parse_partitions(cdev, np);
187
26
  of_partitions_register_fixup(cdev);
188
189
26
  return of_platform_populate(np, NULL, dev);
190
26
}
191
192
static __maybe_unused struct of_device_id hostfile_dt_ids[] = {
193
  {
194
    .compatible = "barebox,hostfile",
195
  }, {
196
    /* sentinel */
197
  }
198
};
199
MODULE_DEVICE_TABLE(of, hostfile_dt_ids);
200
201
static struct driver hf_drv = {
202
  .name  = "hostfile",
203
  .of_compatible = DRV_OF_COMPAT(hostfile_dt_ids),
204
  .probe = hf_probe,
205
};
206
device_platform_driver(hf_drv);
207
208
static int of_hostfile_fixup(struct device_node *root, void *ctx)
209
0
{
210
0
  struct hf_info *hf = ctx;
211
0
  struct device_node *node;
212
0
  bool name_only = false;
213
0
  int ret;
214
215
0
  node = of_get_child_by_name(root, hf->devname);
216
0
  if (node)
217
0
    name_only = true;
218
0
  else
219
0
    node = of_new_node(root, hf->devname);
220
221
0
  ret = of_property_write_string(node, "barebox,filename", hf->filename);
222
0
  if (ret)
223
0
    return ret;
224
225
0
  if (name_only)
226
0
    return 0;
227
228
0
  ret = of_property_write_string(node, "compatible", hostfile_dt_ids->compatible);
229
0
  if (ret)
230
0
    return ret;
231
232
0
  ret = of_property_write_bool(node, "barebox,blockdev", hf->is_blockdev);
233
0
  if (ret)
234
0
    return ret;
235
236
0
  ret = of_property_write_bool(node, "barebox,cdev", hf->is_cdev);
237
0
  if (ret)
238
0
    return ret;
239
240
0
  return of_property_write_bool(node, "barebox,read-only", hf->is_readonly);
241
0
}
242
243
int barebox_register_filedev(struct hf_info *hf)
244
0
{
245
0
  if (!strcmp(hf->devname, "env0"))
246
0
    default_environment_path_set("/dev/env0");
247
248
0
  return of_register_fixup(of_hostfile_fixup, hf);
249
0
}
250
251
static int of_hostfile_map_fixup(struct device_node *root, void *ctx)
252
26
{
253
26
  struct device_node *node;
254
26
  int ret;
255
256
26
  for_each_compatible_node_from(node, root, NULL, "barebox,stickypage") {
257
26
    char *filename;
258
259
26
    filename = linux_get_stickypage_path();
260
26
    if (!filename) {
261
0
      pr_err("error allocating stickypage\n");
262
0
      continue;
263
0
    }
264
265
26
    of_property_write_string(node, "barebox,filename", filename);
266
26
    of_property_write_string(node, "compatible", "barebox,hostfile");
267
26
  }
268
269
26
  for_each_compatible_node_from(node, root, NULL, "barebox,hostfile") {
270
26
    struct hf_info hf = {};
271
26
    uint64_t reg[2] = {};
272
273
26
    hf.devname = node->name;
274
275
26
    ret = of_property_read_string(node, "barebox,filename", &hf.filename);
276
26
    if (ret) {
277
0
      pr_err("skipping nameless hostfile %s\n", hf.devname);
278
0
      continue;
279
0
    }
280
281
26
    hf.is_blockdev = of_property_read_bool(node, "barebox,blockdev");
282
26
    hf.is_cdev = of_property_read_bool(node, "barebox,cdev");
283
26
    hf.is_readonly = of_property_read_bool(node, "barebox,read-only");
284
285
26
    of_property_read_u64_array(node, "reg", reg, ARRAY_SIZE(reg));
286
287
26
    hf.base = reg[0];
288
26
    hf.size = reg[1];
289
290
26
    ret = linux_open_hostfile(&hf);
291
26
    if (ret)
292
0
      continue;
293
294
26
    reg[0] = hf.base;
295
26
    reg[1] = hf.size;
296
297
26
    of_property_write_u64_array(node, "reg", reg, ARRAY_SIZE(reg));
298
26
    of_property_write_bool(node, "barebox,blockdev", hf.is_blockdev);
299
26
    of_property_write_u32(node, "barebox,fd", hf.fd);
300
26
  }
301
302
26
  return 0;
303
26
}
304
305
static int barebox_fixup_filedevs(void)
306
26
{
307
26
  return of_register_fixup(of_hostfile_map_fixup, NULL);
308
26
}
309
pure_initcall(barebox_fixup_filedevs);