2 * Copyright (C) 2016 IBM Corporation
5 * Thiago Jung Bauermann <bauerman@linux.vnet.ibm.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
13 #include <linux/slab.h>
14 #include <linux/kexec.h>
16 #include <linux/memblock.h>
17 #include <linux/libfdt.h>
19 static int get_addr_size_cells(int *addr_cells
, int *size_cells
)
21 struct device_node
*root
;
23 root
= of_find_node_by_path("/");
27 *addr_cells
= of_n_addr_cells(root
);
28 *size_cells
= of_n_size_cells(root
);
35 static int do_get_kexec_buffer(const void *prop
, int len
, unsigned long *addr
,
38 int ret
, addr_cells
, size_cells
;
40 ret
= get_addr_size_cells(&addr_cells
, &size_cells
);
44 if (len
< 4 * (addr_cells
+ size_cells
))
47 *addr
= of_read_number(prop
, addr_cells
);
48 *size
= of_read_number(prop
+ 4 * addr_cells
, size_cells
);
54 * ima_get_kexec_buffer - get IMA buffer from the previous kernel
55 * @addr: On successful return, set to point to the buffer contents.
56 * @size: On successful return, set to the buffer size.
58 * Return: 0 on success, negative errno on error.
60 int ima_get_kexec_buffer(void **addr
, size_t *size
)
63 unsigned long tmp_addr
;
67 prop
= of_get_property(of_chosen
, "linux,ima-kexec-buffer", &len
);
71 ret
= do_get_kexec_buffer(prop
, len
, &tmp_addr
, &tmp_size
);
75 *addr
= __va(tmp_addr
);
82 * ima_free_kexec_buffer - free memory used by the IMA buffer
84 int ima_free_kexec_buffer(void)
89 struct property
*prop
;
91 prop
= of_find_property(of_chosen
, "linux,ima-kexec-buffer", NULL
);
95 ret
= do_get_kexec_buffer(prop
->value
, prop
->length
, &addr
, &size
);
99 ret
= of_remove_property(of_chosen
, prop
);
103 return memblock_free(addr
, size
);
108 * remove_ima_buffer - remove the IMA buffer property and reservation from @fdt
110 * The IMA measurement buffer is of no use to a subsequent kernel, so we always
111 * remove it from the device tree.
113 void remove_ima_buffer(void *fdt
, int chosen_node
)
120 prop
= fdt_getprop(fdt
, chosen_node
, "linux,ima-kexec-buffer", &len
);
124 ret
= do_get_kexec_buffer(prop
, len
, &addr
, &size
);
125 fdt_delprop(fdt
, chosen_node
, "linux,ima-kexec-buffer");
129 ret
= delete_fdt_mem_rsv(fdt
, addr
, size
);
131 pr_debug("Removed old IMA buffer reservation.\n");
134 #ifdef CONFIG_IMA_KEXEC
136 * arch_ima_add_kexec_buffer - do arch-specific steps to add the IMA buffer
138 * Architectures should use this function to pass on the IMA buffer
139 * information to the next kernel.
141 * Return: 0 on success, negative errno on error.
143 int arch_ima_add_kexec_buffer(struct kimage
*image
, unsigned long load_addr
,
146 image
->arch
.ima_buffer_addr
= load_addr
;
147 image
->arch
.ima_buffer_size
= size
;
152 static int write_number(void *p
, u64 value
, int cells
)
160 tmp
= cpu_to_be32(value
);
161 memcpy(p
, &tmp
, sizeof(tmp
));
162 } else if (cells
== 2) {
165 tmp
= cpu_to_be64(value
);
166 memcpy(p
, &tmp
, sizeof(tmp
));
174 * setup_ima_buffer - add IMA buffer information to the fdt
175 * @image: kexec image being loaded.
176 * @fdt: Flattened device tree for the next kernel.
177 * @chosen_node: Offset to the chosen node.
179 * Return: 0 on success, or negative errno on error.
181 int setup_ima_buffer(const struct kimage
*image
, void *fdt
, int chosen_node
)
183 int ret
, addr_cells
, size_cells
, entry_size
;
186 remove_ima_buffer(fdt
, chosen_node
);
187 if (!image
->arch
.ima_buffer_size
)
190 ret
= get_addr_size_cells(&addr_cells
, &size_cells
);
194 entry_size
= 4 * (addr_cells
+ size_cells
);
196 if (entry_size
> sizeof(value
))
199 ret
= write_number(value
, image
->arch
.ima_buffer_addr
, addr_cells
);
203 ret
= write_number(value
+ 4 * addr_cells
, image
->arch
.ima_buffer_size
,
208 ret
= fdt_setprop(fdt
, chosen_node
, "linux,ima-kexec-buffer", value
,
213 ret
= fdt_add_mem_rsv(fdt
, image
->arch
.ima_buffer_addr
,
214 image
->arch
.ima_buffer_size
);
218 pr_debug("IMA buffer at 0x%llx, size = 0x%zx\n",
219 image
->arch
.ima_buffer_addr
, image
->arch
.ima_buffer_size
);
223 #endif /* CONFIG_IMA_KEXEC */