FreeNOS
BootImageCreate.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2009 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <Vector.h>
19#include <ExecutableFormat.h>
20#include <BootImage.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <errno.h>
25#include <limits.h>
26#include <sys/stat.h>
27#include "BootImageCreate.h"
28
30 : Application(argc, argv)
31{
32 parser().setDescription("Create system boot image");
33 parser().registerFlag('p', "prefix", "Prefix each entry from the config file with the given path");
34 parser().registerPositional("CONFFILE", "Configuration file for the boot image");
35 parser().registerPositional("OUTFILE", "Output file name of the boot image");
36}
37
41
43{
44 printf("%s", string);
45 return Success;
46}
47
49 const char *prefix,
50 Vector<BootEntry *> *entries)
51{
52 char line[PATH_MAX];
53 const char *prog = *(parser().name());
54 const char *symbolname = 0;
56 Size totalBytes = 0, totalEntries = 0;
58 FILE *fp;
59 ExecutableFormat *format;
60 size_t prefix_len = prefix ? strlen(prefix) : 0;
61
62 // Open configuration file
63 if ((fp = fopen(conf_file, "r")) == NULL)
64 {
65 fprintf(stderr, "%s: failed to open `%s': %s\r\n",
66 prog, conf_file, strerror(errno));
68 }
69
70 // Read out lines
71 while (fgets(line, sizeof(line), fp) != NULL)
72 {
73 // Allocate new boot entry
74 entry = new BootEntry;
75
76 // Remove trailing newline
77 if (strlen(line) < sizeof(line) - 1)
78 line[strlen(line)-1] = 0;
79
80 // Get boot symbol type
81 if (strncmp(line, "BootProgram ", 12) == 0) {
83 symbolname = line + 12;
84 } else if (strncmp(line, "BootPrivProgram ", 16) == 0) {
85 entry->symbol.type = BootPrivProgram;
86 symbolname = line + 16;
87 } else if (strncmp(line, "BootData ", 9) == 0) {
88 entry->symbol.type = BootData;
89 symbolname = line + 9;
90 } else {
91 fprintf(stderr, "%s: symbol type unknown in line: %s\r\n",
92 prog, line);
94 }
95
96 // Fill boot symbol name first
97 line[sizeof(line)-1] = 0;
98 strncpy(entry->symbol.name, symbolname, BOOTIMAGE_NAMELEN);
99
100 // Append path prefix, if set
101 if (prefix_len && prefix_len < BOOTIMAGE_NAMELEN)
102 {
103 char tmp[PATH_MAX];
104 snprintf(tmp, sizeof(tmp), "%s/%s", prefix, symbolname);
105 strncpy(line, tmp, sizeof(line));
106 symbolname = line;
107 }
108
109 // Find the file
110 struct stat st;
111 if (stat(symbolname, &st) == -1)
112 {
113 fprintf(stderr, "%s: failed to stat `%s': %s\r\n",
114 prog, symbolname, strerror(errno));
116 }
117 // Allocate buffer
118 entry->data = new u8[st.st_size];
119
120 // Read the file
121 FILE *entry_fd = fopen(symbolname, "r");
122 if (!entry_fd)
123 {
124 fprintf(stderr, "%s: failed to open `%s': %s\r\n",
125 prog, symbolname, strerror(errno));
127 }
128 if (fread(entry->data, st.st_size, 1, entry_fd) != 1)
129 {
130 fprintf(stderr, "%s: failed to fread `%s': %s\r\n",
131 prog, symbolname, strerror(errno));
133 }
134 fclose(entry_fd);
135
136 // Parse as BootProgram using libexec.
137 if (entry->symbol.type == BootProgram || entry->symbol.type == BootPrivProgram)
138 {
140 {
141 fprintf(stderr, "%s: failed to parse executable image format in `%s': %s\r\n",
142 prog, symbolname, strerror(errno));
144 }
145 // Extract memory regions
146 if (format->regions(entry->regions, &num) != ExecutableFormat::Success || num <= 0)
147 {
148 fprintf(stderr, "%s: failed to extract memory regions from `%s': %s\r\n",
149 prog, symbolname, strerror(errno));
151 }
152 entry->numRegions = num;
153
154 format->entry((Address *)&entry->symbol.entry);
155 }
156 // BootData
157 else if (entry->symbol.type == BootData)
158 {
159 // Fill BootEntry
160 entry->symbol.type = BootData;
161 entry->numRegions = 1;
162 entry->regions[0].virt = 0;
163 entry->regions[0].access = Memory::User | Memory::Readable | Memory::Writable;
164 entry->regions[0].dataSize = st.st_size;
165 entry->regions[0].memorySize = st.st_size;
166 entry->regions[0].dataOffset = 0;
167 } else {
168 fprintf(stderr, "%s: unknown boot symbol type: %d\r\n",
169 prog, (uint) entry->symbol.type);
171 }
172 // Insert into Array
173 entries->insert(entry);
174 totalEntries++;
175
176 // Debug out memory sections
177 for (Size i = 0; i < entry->numRegions; i++)
178 {
179 printf("%s[%u]: vaddr=%x size=%u\r\n",
180 symbolname, i, (uint) entry->regions[i].virt,
181 entry->regions[i].memorySize);
182 totalBytes += entry->regions[i].memorySize;
183 }
184 }
185 // Close config file
186 fclose(fp);
187
188 // All done
189 printf("%d entries, %d bytes total\r\n", totalEntries, totalBytes);
190 return totalEntries;
191}
192
194{
196 BootImage image;
197 BootSymbol *symbols;
198 BootSegment *segments;
199 FILE *fp;
200 Size numSegments = 0, dataOffset = 0, lastDataOffset = 0;
201 uint segCount = 0;
202 const char *prog = *(parser().name());
203 const char *conf_file = arguments().get("CONFFILE");
204 const char *out_file = arguments().get("OUTFILE");
205 const char *prefix = arguments().get("prefix");
206
207 // Read boot symbols
208 if (readBootSymbols(conf_file, prefix, &input) == 0)
209 {
210 fprintf(stderr, "%s: failed to read boot symbols\r\n", prog);
211 return IOError;
212 }
213
214 // Allocate tables
215 symbols = new BootSymbol[ input.count() ];
216 memset(&image, 0, sizeof(image));
217 memset(symbols, 0, sizeof(BootSymbol) * input.count());
218
219 // Fill in the boot image header
220 image.magic[0] = BOOTIMAGE_MAGIC0;
221 image.magic[1] = BOOTIMAGE_MAGIC1;
223 image.symbolTableOffset = sizeof(BootImage);
224 image.symbolTableCount = input.count();
226 (image.symbolTableCount * sizeof(BootSymbol));
227
228 // Fill in the boot symbols
229 for (Size i = 0; i < input.count(); i++)
230 {
231 strncpy(symbols[i].name, input[i]->symbol.name, BOOTIMAGE_NAMELEN);
232 symbols[i].type = input[i]->symbol.type;
233 symbols[i].entry = input[i]->symbol.entry;
234 symbols[i].segmentsOffset = numSegments;
235 symbols[i].segmentsCount = input[i]->numRegions;
236 symbols[i].segmentsTotalSize = 0;
237 numSegments += input[i]->numRegions;
238 }
239 // Update BootImage
240 image.segmentsTableCount = numSegments;
241
242 // Now we allocate and clear the segments table
243 segments = new BootSegment[numSegments];
244 memset(segments, 0, sizeof(BootSegment) * numSegments);
245
246 // Point segment data after the segments table
247 dataOffset = image.segmentsTableOffset +
248 image.segmentsTableCount * sizeof(BootSegment);
249 dataOffset += PageSize - (dataOffset % PageSize);
250
251 // Fill the segments table by looping symbols
252 for (Size i = 0; i < input.count(); i++)
253 {
254 // Loop the symbol segments
255 for (Size j = 0; j < input[i]->numRegions; j++)
256 {
257 // Fill in the segment
258 segments[segCount].virtualAddress = input[i]->regions[j].virt;
259 segments[segCount].size = input[i]->regions[j].memorySize;
260 segments[segCount].offset = dataOffset;
261
262 // Increment total segments size
263 symbols[i].segmentsTotalSize += segments[segCount].size;
264
265 // Increment data pointer. Align on memory page boundary
266 dataOffset += segments[i].size;
267 lastDataOffset = dataOffset;
268 dataOffset += PageSize - (dataOffset % PageSize);
269 segCount++;
270 }
271 }
272 // Fill in the bootImageSize field
273 image.bootImageSize = lastDataOffset;
274
275 // Open boot image for writing
276 if ((fp = fopen(out_file, "w")) == NULL)
277 {
278 fprintf(stderr, "%s: failed to open `%s': %s\r\n",
279 prog, out_file, strerror(errno));
280 return IOError;
281 }
282
283 // Write the final boot image headers
284 if (fwrite(&image, sizeof(image), 1, fp) <= 0 ||
285 fwrite( symbols, sizeof(BootSymbol) * input.count(), 1, fp) <= 0 ||
286 fwrite( segments, sizeof(BootSegment) * numSegments, 1, fp) <= 0)
287 {
288 fprintf(stderr, "%s: failed to write BootImage headers to `%s': %s\r\n",
289 prog, out_file, strerror(errno));
290 return IOError;
291 }
292
293 // Write the contents of the BootSegments
294 for (Size i = 0; i < input.count(); i++)
295 {
296 // Loop regions/segments per boot symbol entry
297 for (Size j = 0; j < input[i]->numRegions; j++)
298 {
299 // Adjust file pointer
300 if (fseek(fp, segments[symbols[i].segmentsOffset].offset,
301 SEEK_SET) == -1)
302 {
303 fprintf(stderr, "%s: failed to seek to BootSegment contents in `%s': %s\r\n",
304 prog, out_file, strerror(errno));
305 return IOError;
306 }
307
308 // Write segment contents
309 if (fwrite(input[i]->data + input[i]->regions[j].dataOffset,
310 input[i]->regions[j].memorySize, 1, fp) <= 0)
311 {
312 fprintf(stderr, "%s: failed to write BootSegment contents to `%s': %s\r\n",
313 prog, out_file, strerror(errno));
314 return IOError;
315 }
316 }
317 }
318 // Close file
319 fclose(fp);
320
321 // Done
322 return Success;
323}
u64 fp
Definition ARM64Control.h:3
u32 entry[]
Definition IntelACPI.h:1
Generic application.
Definition Application.h:39
Result
Result codes.
Definition Application.h:54
const ArgumentContainer & arguments() const
Get program arguments.
ArgumentParser & parser()
Get program arguments parser.
const char * get(const char *name) const
Get argument by name.
void setDescription(const String &desc)
Set program description.
Result registerPositional(const char *name, const char *description, Size count=1)
Register a positional argument.
const String & name() const
Retrieve program name.
Result registerFlag(char arg, const char *name, const char *description)
Register a flag Argument.
Size readBootSymbols(const char *file, const char *prefix, Vector< BootEntry * > *entries)
Read boot symbols using a configuration file.
virtual Result exec()
Execute the application.
virtual Result output(const char *string) const
Print text to output.
virtual ~BootImageCreate()
Destructor.
BootImageCreate(int argc, char **argv)
Constructor.
static const Size PageSize
Size of memory pages as supported by this program.
Abstraction class of various executable formats.
virtual Result regions(Region *regions, Size *count) const =0
Memory regions a program needs at runtime.
static Result find(const u8 *image, const Size size, ExecutableFormat **fmt)
Find a ExecutableFormat which can handle the given format.
virtual Result entry(Address *entry) const =0
Lookup the program entry point.
Vectors are dynamically resizeable Arrays.
Definition Vector.h:42
virtual int insert(const T &item)
Adds the given item to the Vector, if possible.
Definition Vector.h:93
virtual Size count() const
Returns the number of items inside the Vector.
Definition Vector.h:204
#define BOOTENTRY_MAX_REGIONS
Maximum memory regions.
#define BOOTIMAGE_NAMELEN
Maximum length of BootSymbol names.
Definition BootImage.h:39
#define BOOTIMAGE_MAGIC0
First magic byte.
Definition BootImage.h:30
#define BOOTIMAGE_REVISION
Version of the boot image layout.
Definition BootImage.h:36
#define BOOTIMAGE_MAGIC1
Second magic byte.
Definition BootImage.h:33
@ BootProgram
Executable program.
Definition BootImage.h:74
@ BootPrivProgram
Privileged executable program.
Definition BootImage.h:75
@ BootData
Binary data.
Definition BootImage.h:77
#define SEEK_SET
Seek relative to start-of-file.
Definition stdio.h:46
C int strncmp(const char *dest, const char *src, size_t count)
Compare two strings, by only a maximum number of bytes.
Definition strncmp.cpp:20
C size_t strlen(const char *str)
Calculate the length of a string.
Definition strlen.cpp:21
C char * strerror(int errnum)
The strerror function maps the number in errnum to a message string.
Definition strerror.cpp:20
C size_t fwrite(const void *ptr, size_t size, size_t nitems, FILE *stream)
The fwrite() function shall write, from the array pointed to by ptr, up to nitems elements whose size...
Definition fwrite.cpp:24
C int errno
The lvalue errno is used by many functions to return error values.
C void exit(int status)
Terminate a process.
Definition exit.cpp:21
C void * memset(void *dest, int ch, size_t count)
Fill memory with a constant byte.
Definition memset.cpp:20
#define EXIT_FAILURE
Unsuccessful termination.
Definition stdlib.h:36
C int printf(const char *format,...)
Output a formatted string to standard output.
Definition printf.cpp:22
C int fclose(FILE *stream)
Close a stream.
Definition fclose.cpp:23
C size_t fread(void *ptr, size_t size, size_t nitems, FILE *stream)
Binary input.
Definition fread.cpp:24
C int strncpy(char *dest, const char *src, size_t sz)
Copy a string, given a maximum number of bytes.
Definition strncpy.cpp:20
C FILE * fopen(const char *filename, const char *mode)
Open a stream.
Definition fopen.cpp:24
C int snprintf(char *buffer, unsigned int size, const char *fmt,...)
Write a formatted string into a buffer.
Definition snprintf.cpp:22
#define PATH_MAX
Maximum file path length.
Definition limits.h:37
#define NULL
NULL means zero.
Definition Macros.h:39
unsigned long Address
A memory address.
Definition Types.h:131
unsigned int uint
Unsigned integer number.
Definition Types.h:44
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
unsigned char u8
Unsigned 8-bit number.
Definition Types.h:59
@ User
Definition Memory.h:44
@ Readable
Definition Memory.h:41
@ Writable
Definition Memory.h:42
Executable entry for use inside a boot image.
BootSymbol symbol
BootSymbol definition.
BootImage contains executable programs to be loaded at system bootup.
Definition BootImage.h:45
u32 magic[2]
Magic numbers to detect a valid boot image.
Definition BootImage.h:47
u16 symbolTableCount
Number of entries in the symbols table.
Definition BootImage.h:59
u32 segmentsTableOffset
Offset of the segments table.
Definition BootImage.h:62
u16 segmentsTableCount
Number of entries in the segments table.
Definition BootImage.h:65
u32 symbolTableOffset
Offset of the symbol table.
Definition BootImage.h:56
u8 layoutRevision
Version of the boot image layout.
Definition BootImage.h:50
u32 bootImageSize
Total size of the boot image in bytes.
Definition BootImage.h:53
Memory segment.
Definition BootImage.h:110
u32 size
Total size of the segment.
Definition BootImage.h:115
u32 virtualAddress
Virtual memory address to load the segment.
Definition BootImage.h:112
u32 offset
Offset in the boot image of the segment contents.
Definition BootImage.h:118
Program embedded in the BootImage.
Definition BootImage.h:85
u32 segmentsTotalSize
Total size of the BootSymbol segments.
Definition BootImage.h:102
u16 segmentsCount
Number of contiguous entries in the segment table.
Definition BootImage.h:99
u32 entry
Program entry point (only valid for BootProgram symbols).
Definition BootImage.h:93
u32 segmentsOffset
Offset in the segments table.
Definition BootImage.h:96
BootSymbolType type
Type of boot symbol.
Definition BootImage.h:90
A structure containing information about a file.
Definition stdio.h:61
The <sys/stat.h> header shall define the stat structure.
Definition stat.h:177
off_t st_size
For regular files, the file size in bytes.
Definition stat.h:226