1
#include "romfile_loader.h"
2
#include "byteorder.h" // leXX_to_cpu/cpu_to_leXX
3
#include "util.h" // checksum
4
#include "string.h" // strcmp
5
#include "romfile.h" // struct romfile_s
6
#include "malloc.h" // Zone*, _malloc
7
#include "list.h" // struct hlist_node
8
#include "output.h" // warn_*
9
#include "paravirt.h" // qemu_cfg_write_file
11
struct romfile_loader_file {
12
struct romfile_s *file;
15
struct romfile_loader_files {
17
struct romfile_loader_file files[];
20
// Data structures for storing "write pointer" entries for possible replay
21
struct romfile_wr_pointer_entry {
26
struct hlist_node node;
28
static struct hlist_head romfile_pointer_list;
30
static struct romfile_loader_file *
31
romfile_loader_find(const char *name,
32
struct romfile_loader_files *files)
35
if (name[ROMFILE_LOADER_FILESZ - 1])
37
for (i = 0; i < files->nfiles; ++i)
38
if (!strcmp(files->files[i].file->name, name))
39
return &files->files[i];
43
// Replay "write pointer" entries back to QEMU
44
void romfile_fw_cfg_resume(void)
49
struct romfile_wr_pointer_entry *entry;
50
hlist_for_each_entry(entry, &romfile_pointer_list, node) {
51
qemu_cfg_write_file_simple(&entry->pointer, entry->key,
52
entry->offset, entry->ptr_size);
56
static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
57
struct romfile_loader_files *files)
60
struct romfile_loader_file *file = &files->files[files->nfiles];
63
unsigned alloc_align = le32_to_cpu(entry->alloc.align);
65
if (alloc_align & (alloc_align - 1))
68
switch (entry->alloc.zone) {
69
case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
72
case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
78
if (alloc_align < MALLOC_MIN_ALIGN)
79
alloc_align = MALLOC_MIN_ALIGN;
80
if (entry->alloc.file[ROMFILE_LOADER_FILESZ - 1])
82
file->file = romfile_find(entry->alloc.file);
83
if (!file->file || !file->file->size)
85
data = _malloc(zone, file->file->size, alloc_align);
90
ret = file->file->copy(file->file, data, file->file->size);
91
if (ret != file->file->size)
100
warn_internalerror();
103
static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
104
struct romfile_loader_files *files)
106
struct romfile_loader_file *dest_file;
107
struct romfile_loader_file *src_file;
108
unsigned offset = le32_to_cpu(entry->pointer.offset);
111
dest_file = romfile_loader_find(entry->pointer.dest_file, files);
112
src_file = romfile_loader_find(entry->pointer.src_file, files);
114
if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
115
offset + entry->pointer.size < offset ||
116
offset + entry->pointer.size > dest_file->file->size ||
117
entry->pointer.size < 1 || entry->pointer.size > 8 ||
118
entry->pointer.size & (entry->pointer.size - 1))
121
memcpy(&pointer, dest_file->data + offset, entry->pointer.size);
122
pointer = le64_to_cpu(pointer);
123
pointer += (unsigned long)src_file->data;
124
pointer = cpu_to_le64(pointer);
125
memcpy(dest_file->data + offset, &pointer, entry->pointer.size);
129
warn_internalerror();
132
static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry,
133
struct romfile_loader_files *files)
135
struct romfile_loader_file *file;
136
unsigned offset = le32_to_cpu(entry->cksum.offset);
137
unsigned start = le32_to_cpu(entry->cksum.start);
138
unsigned len = le32_to_cpu(entry->cksum.length);
141
file = romfile_loader_find(entry->cksum.file, files);
143
if (!file || !file->data || offset >= file->file->size ||
144
start + len < start || start + len > file->file->size)
147
data = file->data + offset;
148
*data -= checksum(file->data + start, len);
152
warn_internalerror();
155
static void romfile_loader_write_pointer(struct romfile_loader_entry_s *entry,
156
struct romfile_loader_files *files)
158
struct romfile_s *dest_file;
159
struct romfile_loader_file *src_file;
160
unsigned dst_offset = le32_to_cpu(entry->wr_pointer.dst_offset);
161
unsigned src_offset = le32_to_cpu(entry->wr_pointer.src_offset);
164
/* Writing back to a file that may not be loaded in RAM */
165
dest_file = romfile_find(entry->wr_pointer.dest_file);
166
src_file = romfile_loader_find(entry->wr_pointer.src_file, files);
168
if (!dest_file || !src_file || !src_file->data ||
169
dst_offset + entry->wr_pointer.size < dst_offset ||
170
dst_offset + entry->wr_pointer.size > dest_file->size ||
171
src_offset >= src_file->file->size ||
172
entry->wr_pointer.size < 1 || entry->wr_pointer.size > 8 ||
173
entry->wr_pointer.size & (entry->wr_pointer.size - 1)) {
177
pointer = (unsigned long)src_file->data + src_offset;
178
/* Make sure the pointer fits within wr_pointer.size */
179
if ((entry->wr_pointer.size != sizeof(u64)) &&
180
((pointer >> (entry->wr_pointer.size * 8)) > 0)) {
183
pointer = cpu_to_le64(pointer);
185
/* Only supported on QEMU */
186
if (qemu_cfg_write_file(&pointer, dest_file, dst_offset,
187
entry->wr_pointer.size) != entry->wr_pointer.size) {
191
/* Store the info so it can replayed later if necessary */
192
struct romfile_wr_pointer_entry *store = malloc_high(sizeof(*store));
197
store->pointer = pointer;
198
store->key = qemu_get_romfile_key(dest_file);
199
store->offset = dst_offset;
200
store->ptr_size = entry->wr_pointer.size;
201
hlist_add_head(&store->node, &romfile_pointer_list);
205
warn_internalerror();
208
int romfile_loader_execute(const char *name)
210
struct romfile_loader_entry_s *entry;
211
int size, offset = 0, nfiles;
212
struct romfile_loader_files *files;
213
void *data = romfile_loadfile(name, &size);
217
if (size % sizeof(*entry)) {
218
warn_internalerror();
222
/* (over)estimate the number of files to load. */
223
nfiles = size / sizeof(*entry);
224
files = malloc_tmp(sizeof(*files) + nfiles * sizeof(files->files[0]));
231
for (offset = 0; offset < size; offset += sizeof(*entry)) {
232
entry = data + offset;
233
switch (le32_to_cpu(entry->command)) {
234
case ROMFILE_LOADER_COMMAND_ALLOCATE:
235
romfile_loader_allocate(entry, files);
237
case ROMFILE_LOADER_COMMAND_ADD_POINTER:
238
romfile_loader_add_pointer(entry, files);
240
case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
241
romfile_loader_add_checksum(entry, files);
243
case ROMFILE_LOADER_COMMAND_WRITE_POINTER:
244
romfile_loader_write_pointer(entry, files);
247
/* Skip commands that we don't recognize. */