"Das U-Boot" Source Tree
at master 148 lines 3.1 kB view raw
1// 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 <blk.h> 13#include <bootdev.h> 14#include <dm.h> 15#include <log.h> 16#include <malloc.h> 17#include <os.h> 18#include <sandbox_host.h> 19#include <dm/device-internal.h> 20 21static int host_sb_attach_file(struct udevice *dev, const char *filename) 22{ 23 struct host_sb_plat *plat = dev_get_plat(dev); 24 struct blk_desc *desc; 25 struct udevice *blk; 26 int ret, fd; 27 off_t 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 if (size % desc->blksz) { 61 printf("The size of host backing file '%s' is not multiple of " 62 "the device block size\n", filename); 63 ret = -EINVAL; 64 goto err_fname; 65 } 66 desc->lba = size / desc->blksz; 67 68 /* write this in last, when nothing can go wrong */ 69 plat = dev_get_plat(dev); 70 plat->fd = fd; 71 plat->filename = fname; 72 73 return 0; 74 75err_fname: 76 os_close(fd); 77 78 return ret; 79} 80 81static int host_sb_detach_file(struct udevice *dev) 82{ 83 struct host_sb_plat *plat = dev_get_plat(dev); 84 int ret; 85 86 if (!plat->fd) 87 return log_msg_ret("fd", -ENOENT); 88 89 ret = device_remove(dev, DM_REMOVE_NORMAL); 90 if (ret) 91 return log_msg_ret("rem", ret); 92 93 /* Unbind all children */ 94 ret = device_chld_unbind(dev, NULL); 95 if (ret) 96 return log_msg_ret("unb", ret); 97 98 os_close(plat->fd); 99 plat->fd = 0; 100 free(plat->filename); 101 free(plat->label); 102 103 return 0; 104} 105 106static int host_sb_bind(struct udevice *dev) 107{ 108 struct udevice *blk, *bdev; 109 struct blk_desc *desc; 110 int ret; 111 112 ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST, 113 dev_seq(dev), DEFAULT_BLKSZ, 0, &blk); 114 if (ret) 115 return log_msg_ret("blk", ret); 116 117 desc = dev_get_uclass_plat(blk); 118 snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot"); 119 snprintf(desc->product, BLK_PRD_SIZE, "hostfile"); 120 snprintf(desc->revision, BLK_REV_SIZE, "1.0"); 121 122 if (CONFIG_IS_ENABLED(BOOTSTD)) { 123 ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev); 124 if (ret) 125 return log_msg_ret("bd", ret); 126 } 127 128 return 0; 129} 130 131static struct host_ops host_sb_ops = { 132 .attach_file = host_sb_attach_file, 133 .detach_file = host_sb_detach_file, 134}; 135 136static const struct udevice_id host_ids[] = { 137 { .compatible = "sandbox,host" }, 138 { } 139}; 140 141U_BOOT_DRIVER(host_sb_drv) = { 142 .name = "host_sb_drv", 143 .id = UCLASS_HOST, 144 .of_match = host_ids, 145 .ops = &host_sb_ops, 146 .bind = host_sb_bind, 147 .plat_auto = sizeof(struct host_sb_plat), 148};