1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <libfdt.h>
#include <stdio.h>
#include <stdlib.h>
#include "kexec.h"
#include "dt-ops.h"
static const char n_chosen[] = "chosen";
static const char p_bootargs[] = "bootargs";
static const char p_initrd_start[] = "linux,initrd-start";
static const char p_initrd_end[] = "linux,initrd-end";
int dtb_set_initrd(char **dtb, off_t *dtb_size, off_t start, off_t end)
{
int result;
uint64_t value;
dbgprintf("%s: start %jd, end %jd, size %jd (%jd KiB)\n",
__func__, (intmax_t)start, (intmax_t)end,
(intmax_t)(end - start),
(intmax_t)(end - start) / 1024);
value = cpu_to_fdt64(start);
result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_start,
&value, sizeof(value));
if (result)
return result;
value = cpu_to_fdt64(end);
result = dtb_set_property(dtb, dtb_size, n_chosen, p_initrd_end,
&value, sizeof(value));
if (result) {
dtb_delete_property(*dtb, n_chosen, p_initrd_start);
return result;
}
return 0;
}
void dtb_clear_initrd(char **dtb, off_t *dtb_size)
{
dtb_delete_property(*dtb, n_chosen, p_initrd_start);
dtb_delete_property(*dtb, n_chosen, p_initrd_end);
}
int dtb_set_bootargs(char **dtb, off_t *dtb_size, const char *command_line)
{
return dtb_set_property(dtb, dtb_size, n_chosen, p_bootargs,
command_line, strlen(command_line) + 1);
}
int dtb_set_property(char **dtb, off_t *dtb_size, const char *node,
const char *prop, const void *value, int value_len)
{
int result;
int nodeoffset;
void *new_dtb;
int new_size;
char *new_node = NULL;
value_len = FDT_TAGALIGN(value_len);
new_size = FDT_TAGALIGN(*dtb_size + fdt_node_len(node)
+ fdt_prop_len(prop, value_len));
new_dtb = malloc(new_size);
if (!new_dtb) {
dbgprintf("%s: malloc failed\n", __func__);
return -ENOMEM;
}
result = fdt_open_into(*dtb, new_dtb, new_size);
if (result) {
dbgprintf("%s: fdt_open_into failed: %s\n", __func__,
fdt_strerror(result));
goto on_error;
}
new_node = malloc(strlen("/") + strlen(node) + 1);
if (!new_node) {
dbgprintf("%s: malloc failed\n", __func__);
result = -ENOMEM;
goto on_error;
}
strcpy(new_node, "/");
strcat(new_node, node);
nodeoffset = fdt_path_offset(new_dtb, new_node);
if (nodeoffset == -FDT_ERR_NOTFOUND) {
result = fdt_add_subnode(new_dtb, 0, node);
if (result < 0) {
dbgprintf("%s: fdt_add_subnode failed: %s\n", __func__,
fdt_strerror(result));
goto on_error;
}
nodeoffset = result;
} else if (nodeoffset < 0) {
dbgprintf("%s: fdt_path_offset failed: %s\n", __func__,
fdt_strerror(nodeoffset));
goto on_error;
}
result = fdt_setprop(new_dtb, nodeoffset, prop, value, value_len);
if (result) {
dbgprintf("%s: fdt_setprop failed: %s\n", __func__,
fdt_strerror(result));
goto on_error;
}
/*
* Can't call free on dtb since dtb may have been mmaped by
* slurp_file().
*/
result = fdt_pack(new_dtb);
if (result)
dbgprintf("%s: Unable to pack device tree: %s\n", __func__,
fdt_strerror(result));
*dtb = new_dtb;
*dtb_size = fdt_totalsize(*dtb);
return 0;
on_error:
free(new_dtb);
free(new_node);
return result;
}
int dtb_delete_property(char *dtb, const char *node, const char *prop)
{
int result, nodeoffset;
char *new_node = NULL;
new_node = malloc(strlen("/") + strlen(node) + 1);
if (!new_node) {
dbgprintf("%s: malloc failed\n", __func__);
return -ENOMEM;
}
strcpy(new_node, "/");
strcat(new_node, node);
nodeoffset = fdt_path_offset(dtb, new_node);
if (nodeoffset < 0) {
dbgprintf("%s: fdt_path_offset failed: %s\n", __func__,
fdt_strerror(nodeoffset));
free(new_node);
return nodeoffset;
}
result = fdt_delprop(dtb, nodeoffset, prop);
if (result)
dbgprintf("%s: fdt_delprop failed: %s\n", __func__,
fdt_strerror(nodeoffset));
free(new_node);
return result;
}
|