summaryrefslogtreecommitdiff
path: root/lib/binman.c
blob: cfe1e5f80710ea7eec651176d0452ac80987b926 (plain)
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
// SPDX-License-Identifier: Intel
/*
 * Access to binman information at runtime
 *
 * Copyright 2019 Google LLC
 * Written by Simon Glass <sjg@chromium.org>
 */

#include <common.h>
#include <binman.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
#include <mapmem.h>

/**
 * struct binman_info - Information needed by the binman library
 *
 * @image: Node describing the image we are running from
 * @rom_offset: Offset from an image_pos to the memory-mapped address, or
 *	ROM_OFFSET_NONE if the ROM is not memory-mapped. Can be positive or
 *	negative
 */
struct binman_info {
	ofnode image;
	int rom_offset;
};

#define ROM_OFFSET_NONE		(-1)

static struct binman_info *binman;

/**
 * find_image_node() - Find the top-level binman node
 *
 * Finds the binman node which can be used to load entries. The correct node
 * depends on whether multiple-images is in use.
 *
 * @nodep: Returns the node found, on success
 * Return: 0 if OK, , -EINVAL if there is no /binman node, -ECHILD if multiple
 * images are being used but the first image is not available
 */
static int find_image_node(ofnode *nodep)
{
	ofnode node;

	node = ofnode_path("/binman");
	if (!ofnode_valid(node))
		return log_msg_ret("binman node", -EINVAL);
	if (ofnode_read_bool(node, "multiple-images")) {
		node = ofnode_first_subnode(node);

		if (!ofnode_valid(node))
			return log_msg_ret("first image", -ECHILD);
	}
	*nodep = node;

	return 0;
}

static int binman_entry_find_internal(ofnode node, const char *name,
				      struct binman_entry *entry)
{
	int ret;

	if (!ofnode_valid(node))
		node = binman->image;
	node = ofnode_find_subnode(node, name);
	if (!ofnode_valid(node))
		return log_msg_ret("node", -ENOENT);

	ret = ofnode_read_u32(node, "image-pos", &entry->image_pos);
	if (ret)
		return log_msg_ret("image-pos", ret);
	ret = ofnode_read_u32(node, "size", &entry->size);
	if (ret)
		return log_msg_ret("size", ret);

	return 0;
}

int binman_entry_find(const char *name, struct binman_entry *entry)
{
	return binman_entry_find_internal(binman->image, name, entry);
}

int binman_entry_map(ofnode parent, const char *name, void **bufp, int *sizep)
{
	struct binman_entry entry;
	int ret;

	if (binman->rom_offset == ROM_OFFSET_NONE)
		return -EPERM;
	ret = binman_entry_find_internal(parent, name, &entry);
	if (ret)
		return log_msg_ret("entry", ret);
	if (sizep)
		*sizep = entry.size;
	*bufp = map_sysmem(entry.image_pos + binman->rom_offset, entry.size);

	return 0;
}

ofnode binman_section_find_node(const char *name)
{
	return ofnode_find_subnode(binman->image, name);
}

void binman_set_rom_offset(int rom_offset)
{
	binman->rom_offset = rom_offset;
}

int binman_get_rom_offset(void)
{
	return binman->rom_offset;
}

int binman_select_subnode(const char *name)
{
	ofnode node;
	int ret;

	ret = find_image_node(&node);
	if (ret)
		return log_msg_ret("main", -ENOENT);
	node = ofnode_find_subnode(node, name);
	if (!ofnode_valid(node))
		return log_msg_ret("node", -ENOENT);
	binman->image = node;
	log_info("binman: Selected image subnode '%s'\n",
		 ofnode_get_name(binman->image));

	return 0;
}

int binman_init(void)
{
	int ret;

	binman = malloc(sizeof(struct binman_info));
	if (!binman)
		return log_msg_ret("space for binman", -ENOMEM);
	ret = find_image_node(&binman->image);
	if (ret)
		return log_msg_ret("node", -ENOENT);
	binman_set_rom_offset(ROM_OFFSET_NONE);
	log_debug("binman: Selected image node '%s'\n",
		  ofnode_get_name(binman->image));

	return 0;
}