"Das U-Boot" Source Tree
at master 236 lines 5.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Uclass implementation for standard boot 4 * 5 * Copyright 2021 Google LLC 6 * Written by Simon Glass <sjg@chromium.org> 7 */ 8 9#include <alist.h> 10#include <bootflow.h> 11#include <bootstd.h> 12#include <dm.h> 13#include <env.h> 14#include <log.h> 15#include <malloc.h> 16#include <dm/device-internal.h> 17#include <dm/lists.h> 18#include <dm/read.h> 19#include <dm/uclass-internal.h> 20 21DECLARE_GLOBAL_DATA_PTR; 22 23/* These are used if filename-prefixes is not present */ 24const char *const default_prefixes[] = {"/", "/boot/", NULL}; 25 26static int bootstd_of_to_plat(struct udevice *dev) 27{ 28 struct bootstd_priv *priv = dev_get_priv(dev); 29 int ret; 30 31 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) { 32 /* Don't check errors since livetree and flattree are different */ 33 ret = dev_read_string_list(dev, "filename-prefixes", 34 &priv->prefixes); 35 dev_read_string_list(dev, "bootdev-order", 36 &priv->bootdev_order); 37 38 priv->theme = ofnode_find_subnode(dev_ofnode(dev), "theme"); 39 } 40 41 return 0; 42} 43 44static void bootstd_clear_glob_(struct bootstd_priv *priv) 45{ 46 struct bootflow *bflow; 47 48 alist_for_each(bflow, &priv->bootflows) 49 bootflow_remove(bflow); 50 alist_empty(&priv->bootflows); 51} 52 53void bootstd_clear_glob(void) 54{ 55 struct bootstd_priv *std; 56 57 if (bootstd_get_priv(&std)) 58 return; 59 60 bootstd_clear_glob_(std); 61} 62 63int bootstd_add_bootflow(struct bootflow *bflow) 64{ 65 struct bootstd_priv *std; 66 int ret; 67 68 ret = bootstd_get_priv(&std); 69 if (ret) 70 return ret; 71 72 ret = std->bootflows.count; 73 bflow = alist_add(&std->bootflows, *bflow); 74 if (!bflow) 75 return log_msg_ret("bf2", -ENOMEM); 76 77 return ret; 78} 79 80int bootstd_clear_bootflows_for_bootdev(struct udevice *dev) 81{ 82 struct bootstd_priv *std = bootstd_try_priv(); 83 struct bootflow *from, *to; 84 85 /* if bootstd does not exist we cannot have any bootflows */ 86 if (!std) 87 return 0; 88 89 /* Drop any bootflows that mention this dev */ 90 alist_for_each_filter(from, to, &std->bootflows) { 91 if (from->dev == dev) 92 bootflow_remove(from); 93 else 94 *to++ = *from; 95 } 96 alist_update_end(&std->bootflows, to); 97 98 return 0; 99} 100 101static int bootstd_remove(struct udevice *dev) 102{ 103 struct bootstd_priv *priv = dev_get_priv(dev); 104 105 free(priv->prefixes); 106 free(priv->bootdev_order); 107 bootstd_clear_glob_(priv); 108 109 return 0; 110} 111 112const char *const *const bootstd_get_bootdev_order(struct udevice *dev, 113 bool *okp) 114{ 115 struct bootstd_priv *std = dev_get_priv(dev); 116 const char *targets = env_get("boot_targets"); 117 118 *okp = true; 119 log_debug("- targets %s %p\n", targets, std->bootdev_order); 120 if (targets && *targets) { 121 str_free_list(std->env_order); 122 std->env_order = str_to_list(targets); 123 if (!std->env_order) { 124 *okp = false; 125 return NULL; 126 } 127 return std->env_order; 128 } 129 130 return std->bootdev_order; 131} 132 133const char *const *const bootstd_get_prefixes(struct udevice *dev) 134{ 135 struct bootstd_priv *std = dev_get_priv(dev); 136 137 return std->prefixes ? std->prefixes : default_prefixes; 138} 139 140struct bootstd_priv *bootstd_try_priv(void) 141{ 142 struct udevice *dev; 143 144 dev = uclass_try_first_device(UCLASS_BOOTSTD); 145 if (!dev || !device_active(dev)) 146 return NULL; 147 148 return dev_get_priv(dev); 149} 150 151int bootstd_get_priv(struct bootstd_priv **stdp) 152{ 153 struct udevice *dev; 154 int ret; 155 156 ret = uclass_first_device_err(UCLASS_BOOTSTD, &dev); 157 if (ret) 158 return ret; 159 *stdp = dev_get_priv(dev); 160 161 return 0; 162} 163 164static int bootstd_probe(struct udevice *dev) 165{ 166 struct bootstd_priv *std = dev_get_priv(dev); 167 168 alist_init_struct(&std->bootflows, struct bootflow); 169 170 return 0; 171} 172 173/* For now, bind the bootmethod device if none are found in the devicetree */ 174int dm_scan_other(bool pre_reloc_only) 175{ 176 struct driver *drv = ll_entry_start(struct driver, driver); 177 const int n_ents = ll_entry_count(struct driver, driver); 178 struct udevice *dev, *bootstd; 179 int i, ret; 180 181 /* These are not needed before relocation */ 182 if (!(gd->flags & GD_FLG_RELOC)) 183 return 0; 184 185 /* Create a bootstd device if needed */ 186 uclass_find_first_device(UCLASS_BOOTSTD, &bootstd); 187 if (!bootstd) { 188 ret = device_bind_driver(gd->dm_root, "bootstd_drv", "bootstd", 189 &bootstd); 190 if (ret) 191 return log_msg_ret("bootstd", ret); 192 } 193 194 /* If there are no bootmeth devices, create them */ 195 uclass_find_first_device(UCLASS_BOOTMETH, &dev); 196 if (dev) 197 return 0; 198 199 for (i = 0; i < n_ents; i++, drv++) { 200 if (drv->id == UCLASS_BOOTMETH) { 201 const char *name = drv->name; 202 203 if (!strncmp("bootmeth_", name, 9)) 204 name += 9; 205 ret = device_bind(bootstd, drv, name, 0, ofnode_null(), 206 &dev); 207 if (ret) 208 return log_msg_ret("meth", ret); 209 } 210 } 211 212 return 0; 213} 214 215static const struct udevice_id bootstd_ids[] = { 216 { .compatible = "u-boot,boot-std" }, 217 { } 218}; 219 220U_BOOT_DRIVER(bootstd_drv) = { 221 .id = UCLASS_BOOTSTD, 222 .name = "bootstd_drv", 223 .of_to_plat = bootstd_of_to_plat, 224 .probe = bootstd_probe, 225 .remove = bootstd_remove, 226 .of_match = bootstd_ids, 227 .priv_auto = sizeof(struct bootstd_priv), 228}; 229 230UCLASS_DRIVER(bootstd) = { 231 .id = UCLASS_BOOTSTD, 232 .name = "bootstd", 233#if CONFIG_IS_ENABLED(OF_REAL) 234 .post_bind = dm_scan_fdt_dev, 235#endif 236};