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 "output.h" // warn_*
9 struct romfile_loader_file {
10 struct romfile_s *file;
13 struct romfile_loader_files {
15 struct romfile_loader_file files[];
18 static struct romfile_loader_file *
19 romfile_loader_find(const char *name,
20 struct romfile_loader_files *files)
23 if (name[ROMFILE_LOADER_FILESZ - 1])
25 for (i = 0; i < files->nfiles; ++i)
26 if (!strcmp(files->files[i].file->name, name))
27 return &files->files[i];
31 static void romfile_loader_allocate(struct romfile_loader_entry_s *entry,
32 struct romfile_loader_files *files)
35 struct romfile_loader_file *file = &files->files[files->nfiles];
38 unsigned alloc_align = le32_to_cpu(entry->alloc_align);
40 if (alloc_align & (alloc_align - 1))
43 switch (entry->alloc_zone) {
44 case ROMFILE_LOADER_ALLOC_ZONE_HIGH:
47 case ROMFILE_LOADER_ALLOC_ZONE_FSEG:
53 if (alloc_align < MALLOC_MIN_ALIGN)
54 alloc_align = MALLOC_MIN_ALIGN;
55 if (entry->alloc_file[ROMFILE_LOADER_FILESZ - 1])
57 file->file = romfile_find(entry->alloc_file);
58 if (!file->file || !file->file->size)
60 data = _malloc(zone, file->file->size, alloc_align);
65 ret = file->file->copy(file->file, data, file->file->size);
66 if (ret != file->file->size)
78 static void romfile_loader_add_pointer(struct romfile_loader_entry_s *entry,
79 struct romfile_loader_files *files)
81 struct romfile_loader_file *dest_file;
82 struct romfile_loader_file *src_file;
83 unsigned offset = le32_to_cpu(entry->pointer_offset);
86 dest_file = romfile_loader_find(entry->pointer_dest_file, files);
87 src_file = romfile_loader_find(entry->pointer_src_file, files);
89 if (!dest_file || !src_file || !dest_file->data || !src_file->data ||
90 offset + entry->pointer_size < offset ||
91 offset + entry->pointer_size > dest_file->file->size ||
92 entry->pointer_size < 1 || entry->pointer_size > 8 ||
93 entry->pointer_size & (entry->pointer_size - 1))
96 memcpy(&pointer, dest_file->data + offset, entry->pointer_size);
97 pointer = le64_to_cpu(pointer);
98 pointer += (unsigned long)src_file->data;
99 pointer = cpu_to_le64(pointer);
100 memcpy(dest_file->data + offset, &pointer, entry->pointer_size);
104 warn_internalerror();
107 static void romfile_loader_add_checksum(struct romfile_loader_entry_s *entry,
108 struct romfile_loader_files *files)
110 struct romfile_loader_file *file;
111 unsigned offset = le32_to_cpu(entry->cksum_offset);
112 unsigned start = le32_to_cpu(entry->cksum_start);
113 unsigned len = le32_to_cpu(entry->cksum_length);
116 file = romfile_loader_find(entry->cksum_file, files);
118 if (!file || !file->data || offset >= file->file->size ||
119 start + len < start || start + len > file->file->size)
122 data = file->data + offset;
123 *data -= checksum(file->data + start, len);
127 warn_internalerror();
130 int romfile_loader_execute(const char *name)
132 struct romfile_loader_entry_s *entry;
133 int size, offset = 0, nfiles;
134 struct romfile_loader_files *files;
135 void *data = romfile_loadfile(name, &size);
139 if (size % sizeof(*entry)) {
140 warn_internalerror();
144 /* (over)estimate the number of files to load. */
145 nfiles = size / sizeof(*entry);
146 files = malloc_tmp(sizeof(*files) + nfiles * sizeof(files->files[0]));
153 for (offset = 0; offset < size; offset += sizeof(*entry)) {
154 entry = data + offset;
155 switch (le32_to_cpu(entry->command)) {
156 case ROMFILE_LOADER_COMMAND_ALLOCATE:
157 romfile_loader_allocate(entry, files);
159 case ROMFILE_LOADER_COMMAND_ADD_POINTER:
160 romfile_loader_add_pointer(entry, files);
162 case ROMFILE_LOADER_COMMAND_ADD_CHECKSUM:
163 romfile_loader_add_checksum(entry, files);
165 /* Skip commands that we don't recognize. */