1 | /* ----------------------------------------------------------------------- * |
---|
2 | * |
---|
3 | * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved |
---|
4 | * Copyright 2009-2013 Intel Corporation; author: H. Peter Anvin |
---|
5 | * |
---|
6 | * Permission is hereby granted, free of charge, to any person |
---|
7 | * obtaining a copy of this software and associated documentation |
---|
8 | * files (the "Software"), to deal in the Software without |
---|
9 | * restriction, including without limitation the rights to use, |
---|
10 | * copy, modify, merge, publish, distribute, sublicense, and/or |
---|
11 | * sell copies of the Software, and to permit persons to whom |
---|
12 | * the Software is furnished to do so, subject to the following |
---|
13 | * conditions: |
---|
14 | * |
---|
15 | * The above copyright notice and this permission notice shall |
---|
16 | * be included in all copies or substantial portions of the Software. |
---|
17 | * |
---|
18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
---|
20 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
21 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
---|
22 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
---|
23 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
---|
24 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
---|
25 | * OTHER DEALINGS IN THE SOFTWARE. |
---|
26 | * |
---|
27 | * ----------------------------------------------------------------------- */ |
---|
28 | |
---|
29 | /* |
---|
30 | * load_linux.c |
---|
31 | * |
---|
32 | * Load a Linux kernel (Image/zImage/bzImage). |
---|
33 | */ |
---|
34 | |
---|
35 | #include <ctype.h> |
---|
36 | #include <stdbool.h> |
---|
37 | #include <stdlib.h> |
---|
38 | #include <inttypes.h> |
---|
39 | #include <string.h> |
---|
40 | #include <minmax.h> |
---|
41 | #include <errno.h> |
---|
42 | #include <suffix_number.h> |
---|
43 | #include <dprintf.h> |
---|
44 | |
---|
45 | #include <syslinux/align.h> |
---|
46 | #include <syslinux/linux.h> |
---|
47 | #include <syslinux/bootrm.h> |
---|
48 | #include <syslinux/movebits.h> |
---|
49 | #include <syslinux/firmware.h> |
---|
50 | #include <syslinux/video.h> |
---|
51 | |
---|
52 | #define BOOT_MAGIC 0xAA55 |
---|
53 | #define LINUX_MAGIC ('H' + ('d' << 8) + ('r' << 16) + ('S' << 24)) |
---|
54 | #define OLD_CMDLINE_MAGIC 0xA33F |
---|
55 | |
---|
56 | /* loadflags */ |
---|
57 | #define LOAD_HIGH 0x01 |
---|
58 | #define CAN_USE_HEAP 0x80 |
---|
59 | |
---|
60 | /* |
---|
61 | * Find the last instance of a particular command line argument |
---|
62 | * (which should include the final =; do not use for boolean arguments) |
---|
63 | * Note: the resulting string is typically not null-terminated. |
---|
64 | */ |
---|
65 | static const char *find_argument(const char *cmdline, const char *argument) |
---|
66 | { |
---|
67 | const char *found = NULL; |
---|
68 | const char *p = cmdline; |
---|
69 | bool was_space = true; |
---|
70 | size_t la = strlen(argument); |
---|
71 | |
---|
72 | while (*p) { |
---|
73 | if (isspace(*p)) { |
---|
74 | was_space = true; |
---|
75 | } else if (was_space) { |
---|
76 | if (!memcmp(p, argument, la)) |
---|
77 | found = p + la; |
---|
78 | was_space = false; |
---|
79 | } |
---|
80 | p++; |
---|
81 | } |
---|
82 | |
---|
83 | return found; |
---|
84 | } |
---|
85 | |
---|
86 | /* Truncate to 32 bits, with saturate */ |
---|
87 | static inline uint32_t saturate32(unsigned long long v) |
---|
88 | { |
---|
89 | return (v > 0xffffffff) ? 0xffffffff : (uint32_t) v; |
---|
90 | } |
---|
91 | |
---|
92 | /* Create the appropriate mappings for the initramfs */ |
---|
93 | static int map_initramfs(struct syslinux_movelist **fraglist, |
---|
94 | struct syslinux_memmap **mmap, |
---|
95 | struct initramfs *initramfs, addr_t addr) |
---|
96 | { |
---|
97 | struct initramfs *ip; |
---|
98 | addr_t next_addr, len, pad; |
---|
99 | |
---|
100 | for (ip = initramfs->next; ip->len; ip = ip->next) { |
---|
101 | len = ip->len; |
---|
102 | next_addr = addr + len; |
---|
103 | |
---|
104 | /* If this isn't the last entry, extend the zero-pad region |
---|
105 | to enforce the alignment of the next chunk. */ |
---|
106 | if (ip->next->len) { |
---|
107 | pad = -next_addr & (ip->next->align - 1); |
---|
108 | len += pad; |
---|
109 | next_addr += pad; |
---|
110 | } |
---|
111 | |
---|
112 | if (ip->data_len) { |
---|
113 | if (syslinux_add_movelist(fraglist, addr, (addr_t) ip->data, len)) |
---|
114 | return -1; |
---|
115 | } |
---|
116 | if (len > ip->data_len) { |
---|
117 | if (syslinux_add_memmap(mmap, addr + ip->data_len, |
---|
118 | len - ip->data_len, SMT_ZERO)) |
---|
119 | return -1; |
---|
120 | } |
---|
121 | addr = next_addr; |
---|
122 | } |
---|
123 | |
---|
124 | return 0; |
---|
125 | } |
---|
126 | |
---|
127 | static size_t calc_cmdline_offset(const struct syslinux_memmap *mmap, |
---|
128 | const struct linux_header *hdr, |
---|
129 | size_t cmdline_size, addr_t base, |
---|
130 | addr_t start) |
---|
131 | { |
---|
132 | size_t max_offset; |
---|
133 | |
---|
134 | if (hdr->version >= 0x0202 && (hdr->loadflags & LOAD_HIGH)) |
---|
135 | max_offset = 0x10000; |
---|
136 | else |
---|
137 | max_offset = 0xfff0 - cmdline_size; |
---|
138 | |
---|
139 | if (!syslinux_memmap_highest(mmap, SMT_FREE, &start, |
---|
140 | cmdline_size, 0xa0000, 16) || |
---|
141 | !syslinux_memmap_highest(mmap, SMT_TERMINAL, &start, |
---|
142 | cmdline_size, 0xa0000, 16)) { |
---|
143 | |
---|
144 | |
---|
145 | return min(start - base, max_offset) & ~15; |
---|
146 | } |
---|
147 | |
---|
148 | dprintf("Unable to find lowmem for cmdline\n"); |
---|
149 | return (0x9ff0 - cmdline_size) & ~15; /* Legacy value: pure hope... */ |
---|
150 | } |
---|
151 | |
---|
152 | int bios_boot_linux(void *kernel_buf, size_t kernel_size, |
---|
153 | struct initramfs *initramfs, |
---|
154 | struct setup_data *setup_data, |
---|
155 | char *cmdline) |
---|
156 | { |
---|
157 | struct linux_header hdr, *whdr; |
---|
158 | size_t real_mode_size, prot_mode_size, base; |
---|
159 | addr_t real_mode_base, prot_mode_base, prot_mode_max; |
---|
160 | addr_t irf_size; |
---|
161 | size_t cmdline_size, cmdline_offset; |
---|
162 | struct setup_data *sdp; |
---|
163 | struct syslinux_rm_regs regs; |
---|
164 | struct syslinux_movelist *fraglist = NULL; |
---|
165 | struct syslinux_memmap *mmap = NULL; |
---|
166 | struct syslinux_memmap *amap = NULL; |
---|
167 | uint32_t memlimit = 0; |
---|
168 | uint16_t video_mode = 0; |
---|
169 | const char *arg; |
---|
170 | |
---|
171 | cmdline_size = strlen(cmdline) + 1; |
---|
172 | |
---|
173 | errno = EINVAL; |
---|
174 | if (kernel_size < 2 * 512) { |
---|
175 | dprintf("Kernel size too small\n"); |
---|
176 | goto bail; |
---|
177 | } |
---|
178 | |
---|
179 | /* Look for specific command-line arguments we care about */ |
---|
180 | if ((arg = find_argument(cmdline, "mem="))) |
---|
181 | memlimit = saturate32(suffix_number(arg)); |
---|
182 | |
---|
183 | if ((arg = find_argument(cmdline, "vga="))) { |
---|
184 | switch (arg[0] | 0x20) { |
---|
185 | case 'a': /* "ask" */ |
---|
186 | video_mode = 0xfffd; |
---|
187 | break; |
---|
188 | case 'e': /* "ext" */ |
---|
189 | video_mode = 0xfffe; |
---|
190 | break; |
---|
191 | case 'n': /* "normal" */ |
---|
192 | video_mode = 0xffff; |
---|
193 | break; |
---|
194 | case 'c': /* "current" */ |
---|
195 | video_mode = 0x0f04; |
---|
196 | break; |
---|
197 | default: |
---|
198 | video_mode = strtoul(arg, NULL, 0); |
---|
199 | break; |
---|
200 | } |
---|
201 | } |
---|
202 | |
---|
203 | /* Copy the header into private storage */ |
---|
204 | /* Use whdr to modify the actual kernel header */ |
---|
205 | memcpy(&hdr, kernel_buf, sizeof hdr); |
---|
206 | whdr = (struct linux_header *)kernel_buf; |
---|
207 | |
---|
208 | if (hdr.boot_flag != BOOT_MAGIC) { |
---|
209 | dprintf("Invalid boot magic\n"); |
---|
210 | goto bail; |
---|
211 | } |
---|
212 | |
---|
213 | if (hdr.header != LINUX_MAGIC) { |
---|
214 | hdr.version = 0x0100; /* Very old kernel */ |
---|
215 | hdr.loadflags = 0; |
---|
216 | } |
---|
217 | |
---|
218 | whdr->vid_mode = video_mode; |
---|
219 | |
---|
220 | if (!hdr.setup_sects) |
---|
221 | hdr.setup_sects = 4; |
---|
222 | |
---|
223 | if (hdr.version < 0x0203 || !hdr.initrd_addr_max) |
---|
224 | hdr.initrd_addr_max = 0x37ffffff; |
---|
225 | |
---|
226 | if (!memlimit && memlimit - 1 > hdr.initrd_addr_max) |
---|
227 | memlimit = hdr.initrd_addr_max + 1; /* Zero for no limit */ |
---|
228 | |
---|
229 | if (hdr.version < 0x0205 || !(hdr.loadflags & LOAD_HIGH)) |
---|
230 | hdr.relocatable_kernel = 0; |
---|
231 | |
---|
232 | if (hdr.version < 0x0206) |
---|
233 | hdr.cmdline_max_len = 256; |
---|
234 | |
---|
235 | if (cmdline_size > hdr.cmdline_max_len) { |
---|
236 | cmdline_size = hdr.cmdline_max_len; |
---|
237 | cmdline[cmdline_size - 1] = '\0'; |
---|
238 | } |
---|
239 | |
---|
240 | real_mode_size = (hdr.setup_sects + 1) << 9; |
---|
241 | real_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x10000 : 0x90000; |
---|
242 | prot_mode_base = (hdr.loadflags & LOAD_HIGH) ? 0x100000 : 0x10000; |
---|
243 | prot_mode_max = (hdr.loadflags & LOAD_HIGH) ? (addr_t)-1 : 0x8ffff; |
---|
244 | prot_mode_size = kernel_size - real_mode_size; |
---|
245 | |
---|
246 | /* Get the memory map */ |
---|
247 | mmap = syslinux_memory_map(); /* Memory map for shuffle_boot */ |
---|
248 | amap = syslinux_dup_memmap(mmap); /* Keep track of available memory */ |
---|
249 | if (!mmap || !amap) { |
---|
250 | errno = ENOMEM; |
---|
251 | goto bail; |
---|
252 | } |
---|
253 | |
---|
254 | cmdline_offset = calc_cmdline_offset(mmap, &hdr, cmdline_size, |
---|
255 | real_mode_base, |
---|
256 | real_mode_base + real_mode_size); |
---|
257 | dprintf("cmdline_offset at 0x%x\n", real_mode_base + cmdline_offset); |
---|
258 | |
---|
259 | if (hdr.version < 0x020a) { |
---|
260 | /* |
---|
261 | * The 3* here is a total fudge factor... it's supposed to |
---|
262 | * account for the fact that the kernel needs to be |
---|
263 | * decompressed, and then followed by the BSS and BRK regions. |
---|
264 | * This doesn't, however, account for the fact that the kernel |
---|
265 | * is decompressed into a whole other place, either. |
---|
266 | */ |
---|
267 | hdr.init_size = 3 * prot_mode_size; |
---|
268 | } |
---|
269 | |
---|
270 | if (!(hdr.loadflags & LOAD_HIGH) && prot_mode_size > 512 * 1024) { |
---|
271 | dprintf("Kernel cannot be loaded low\n"); |
---|
272 | goto bail; |
---|
273 | } |
---|
274 | |
---|
275 | /* Get the size of the initramfs, if there is one */ |
---|
276 | irf_size = initramfs_size(initramfs); |
---|
277 | |
---|
278 | if (irf_size && hdr.version < 0x0200) { |
---|
279 | dprintf("Initrd specified but not supported by kernel\n"); |
---|
280 | goto bail; |
---|
281 | } |
---|
282 | |
---|
283 | if (hdr.version >= 0x0200) { |
---|
284 | whdr->type_of_loader = 0x30; /* SYSLINUX unknown module */ |
---|
285 | if (hdr.version >= 0x0201) { |
---|
286 | whdr->heap_end_ptr = cmdline_offset - 0x0200; |
---|
287 | whdr->loadflags |= CAN_USE_HEAP; |
---|
288 | } |
---|
289 | } |
---|
290 | |
---|
291 | dprintf("Initial memory map:\n"); |
---|
292 | syslinux_dump_memmap(mmap); |
---|
293 | |
---|
294 | /* If the user has specified a memory limit, mark that as unavailable. |
---|
295 | Question: should we mark this off-limit in the mmap as well (meaning |
---|
296 | it's unavailable to the boot loader, which probably has already touched |
---|
297 | some of it), or just in the amap? */ |
---|
298 | if (memlimit) |
---|
299 | if (syslinux_add_memmap(&amap, memlimit, -memlimit, SMT_RESERVED)) { |
---|
300 | errno = ENOMEM; |
---|
301 | goto bail; |
---|
302 | } |
---|
303 | |
---|
304 | /* Place the kernel in memory */ |
---|
305 | |
---|
306 | /* |
---|
307 | * First, find a suitable place for the protected-mode code. If |
---|
308 | * the kernel image is not relocatable, just worry if it fits (it |
---|
309 | * might not even be a Linux image, after all, and for !LOAD_HIGH |
---|
310 | * we end up decompressing into a different location anyway), but |
---|
311 | * if it is, make sure everything fits. |
---|
312 | */ |
---|
313 | base = prot_mode_base; |
---|
314 | if (prot_mode_size && |
---|
315 | syslinux_memmap_find(amap, &base, |
---|
316 | hdr.relocatable_kernel ? |
---|
317 | hdr.init_size : prot_mode_size, |
---|
318 | hdr.relocatable_kernel, hdr.kernel_alignment, |
---|
319 | prot_mode_base, prot_mode_max, |
---|
320 | prot_mode_base, prot_mode_max)) { |
---|
321 | dprintf("Could not find location for protected-mode code\n"); |
---|
322 | goto bail; |
---|
323 | } |
---|
324 | |
---|
325 | whdr->code32_start += base - prot_mode_base; |
---|
326 | |
---|
327 | /* Real mode code */ |
---|
328 | if (syslinux_memmap_find(amap, &real_mode_base, |
---|
329 | cmdline_offset + cmdline_size, true, 16, |
---|
330 | real_mode_base, 0x90000, 0, 640*1024)) { |
---|
331 | dprintf("Could not find location for real-mode code\n"); |
---|
332 | goto bail; |
---|
333 | } |
---|
334 | |
---|
335 | if (syslinux_add_movelist(&fraglist, real_mode_base, (addr_t) kernel_buf, |
---|
336 | real_mode_size)) |
---|
337 | goto bail; |
---|
338 | if (syslinux_add_memmap |
---|
339 | (&amap, real_mode_base, cmdline_offset + cmdline_size, SMT_ALLOC)) { |
---|
340 | errno = ENOMEM; |
---|
341 | goto bail; |
---|
342 | } |
---|
343 | |
---|
344 | /* Zero region between real mode code and cmdline */ |
---|
345 | if (syslinux_add_memmap(&mmap, real_mode_base + real_mode_size, |
---|
346 | cmdline_offset - real_mode_size, SMT_ZERO)) { |
---|
347 | errno = ENOMEM; |
---|
348 | goto bail; |
---|
349 | } |
---|
350 | |
---|
351 | /* Command line */ |
---|
352 | if (syslinux_add_movelist(&fraglist, real_mode_base + cmdline_offset, |
---|
353 | (addr_t) cmdline, cmdline_size)) { |
---|
354 | errno = ENOMEM; |
---|
355 | goto bail; |
---|
356 | } |
---|
357 | if (hdr.version >= 0x0202) { |
---|
358 | whdr->cmd_line_ptr = real_mode_base + cmdline_offset; |
---|
359 | } else { |
---|
360 | whdr->old_cmd_line_magic = OLD_CMDLINE_MAGIC; |
---|
361 | whdr->old_cmd_line_offset = cmdline_offset; |
---|
362 | if (hdr.version >= 0x0200) { |
---|
363 | /* Be paranoid and round up to a multiple of 16 */ |
---|
364 | whdr->setup_move_size = (cmdline_offset + cmdline_size + 15) & ~15; |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | /* Protected-mode code */ |
---|
369 | if (prot_mode_size) { |
---|
370 | if (syslinux_add_movelist(&fraglist, prot_mode_base, |
---|
371 | (addr_t) kernel_buf + real_mode_size, |
---|
372 | prot_mode_size)) { |
---|
373 | errno = ENOMEM; |
---|
374 | goto bail; |
---|
375 | } |
---|
376 | if (syslinux_add_memmap(&amap, prot_mode_base, prot_mode_size, |
---|
377 | SMT_ALLOC)) { |
---|
378 | errno = ENOMEM; |
---|
379 | goto bail; |
---|
380 | } |
---|
381 | } |
---|
382 | |
---|
383 | /* Figure out the size of the initramfs, and where to put it. |
---|
384 | We should put it at the highest possible address which is |
---|
385 | <= hdr.initrd_addr_max, which fits the entire initramfs. */ |
---|
386 | |
---|
387 | if (irf_size) { |
---|
388 | addr_t best_addr = 0; |
---|
389 | struct syslinux_memmap *ml; |
---|
390 | const addr_t align_mask = INITRAMFS_MAX_ALIGN - 1; |
---|
391 | |
---|
392 | if (irf_size) { |
---|
393 | for (ml = amap; ml->type != SMT_END; ml = ml->next) { |
---|
394 | addr_t adj_start = (ml->start + align_mask) & ~align_mask; |
---|
395 | addr_t adj_end = ml->next->start & ~align_mask; |
---|
396 | if (ml->type == SMT_FREE && adj_end - adj_start >= irf_size) |
---|
397 | best_addr = (adj_end - irf_size) & ~align_mask; |
---|
398 | } |
---|
399 | |
---|
400 | if (!best_addr) { |
---|
401 | dprintf("Insufficient memory for initramfs\n"); |
---|
402 | goto bail; |
---|
403 | } |
---|
404 | |
---|
405 | whdr->ramdisk_image = best_addr; |
---|
406 | whdr->ramdisk_size = irf_size; |
---|
407 | |
---|
408 | if (syslinux_add_memmap(&amap, best_addr, irf_size, SMT_ALLOC)) { |
---|
409 | errno = ENOMEM; |
---|
410 | goto bail; |
---|
411 | } |
---|
412 | |
---|
413 | if (map_initramfs(&fraglist, &mmap, initramfs, best_addr)) { |
---|
414 | errno = ENOMEM; |
---|
415 | goto bail; |
---|
416 | } |
---|
417 | } |
---|
418 | } |
---|
419 | |
---|
420 | if (setup_data) { |
---|
421 | uint64_t *prev_ptr = &whdr->setup_data; |
---|
422 | |
---|
423 | for (sdp = setup_data->next; sdp != setup_data; sdp = sdp->next) { |
---|
424 | struct syslinux_memmap *ml; |
---|
425 | const addr_t align_mask = 15; /* Header is 16 bytes */ |
---|
426 | addr_t best_addr = 0; |
---|
427 | size_t size = sdp->hdr.len + sizeof(sdp->hdr); |
---|
428 | |
---|
429 | if (!sdp->data || !sdp->hdr.len) |
---|
430 | continue; |
---|
431 | |
---|
432 | if (hdr.version < 0x0209) { |
---|
433 | /* Setup data not supported */ |
---|
434 | errno = ENXIO; /* Kind of arbitrary... */ |
---|
435 | goto bail; |
---|
436 | } |
---|
437 | |
---|
438 | for (ml = amap; ml->type != SMT_END; ml = ml->next) { |
---|
439 | addr_t adj_start = (ml->start + align_mask) & ~align_mask; |
---|
440 | addr_t adj_end = ml->next->start & ~align_mask; |
---|
441 | |
---|
442 | if (ml->type == SMT_FREE && adj_end - adj_start >= size) |
---|
443 | best_addr = (adj_end - size) & ~align_mask; |
---|
444 | } |
---|
445 | |
---|
446 | if (!best_addr) |
---|
447 | goto bail; |
---|
448 | |
---|
449 | *prev_ptr = best_addr; |
---|
450 | prev_ptr = &sdp->hdr.next; |
---|
451 | |
---|
452 | if (syslinux_add_memmap(&amap, best_addr, size, SMT_ALLOC)) { |
---|
453 | errno = ENOMEM; |
---|
454 | goto bail; |
---|
455 | } |
---|
456 | if (syslinux_add_movelist(&fraglist, best_addr, |
---|
457 | (addr_t)&sdp->hdr, sizeof sdp->hdr)) { |
---|
458 | errno = ENOMEM; |
---|
459 | goto bail; |
---|
460 | } |
---|
461 | if (syslinux_add_movelist(&fraglist, best_addr + sizeof sdp->hdr, |
---|
462 | (addr_t)sdp->data, sdp->hdr.len)) { |
---|
463 | errno = ENOMEM; |
---|
464 | goto bail; |
---|
465 | } |
---|
466 | } |
---|
467 | } |
---|
468 | |
---|
469 | /* Set up the registers on entry */ |
---|
470 | memset(®s, 0, sizeof regs); |
---|
471 | regs.es = regs.ds = regs.ss = regs.fs = regs.gs = real_mode_base >> 4; |
---|
472 | regs.cs = (real_mode_base >> 4) + 0x20; |
---|
473 | /* regs.ip = 0; */ |
---|
474 | /* Linux is OK with sp = 0 = 64K, but perhaps other things aren't... */ |
---|
475 | regs.esp.w[0] = min(cmdline_offset, (size_t) 0xfff0); |
---|
476 | |
---|
477 | dprintf("Final memory map:\n"); |
---|
478 | syslinux_dump_memmap(mmap); |
---|
479 | |
---|
480 | dprintf("Final available map:\n"); |
---|
481 | syslinux_dump_memmap(amap); |
---|
482 | |
---|
483 | dprintf("Initial movelist:\n"); |
---|
484 | syslinux_dump_movelist(fraglist); |
---|
485 | |
---|
486 | if (video_mode != 0x0f04) { |
---|
487 | /* |
---|
488 | * video_mode is not "current", so if we are in graphics mode we |
---|
489 | * need to revert to text mode... |
---|
490 | */ |
---|
491 | dprintf("*** Calling syslinux_force_text_mode()...\n"); |
---|
492 | syslinux_force_text_mode(); |
---|
493 | } else { |
---|
494 | dprintf("*** vga=current, not calling syslinux_force_text_mode()...\n"); |
---|
495 | } |
---|
496 | |
---|
497 | syslinux_shuffle_boot_rm(fraglist, mmap, 0, ®s); |
---|
498 | dprintf("shuffle_boot_rm failed\n"); |
---|
499 | |
---|
500 | bail: |
---|
501 | syslinux_free_movelist(fraglist); |
---|
502 | syslinux_free_memmap(mmap); |
---|
503 | syslinux_free_memmap(amap); |
---|
504 | return -1; |
---|
505 | } |
---|
506 | |
---|
507 | int syslinux_boot_linux(void *kernel_buf, size_t kernel_size, |
---|
508 | struct initramfs *initramfs, |
---|
509 | struct setup_data *setup_data, |
---|
510 | char *cmdline) |
---|
511 | { |
---|
512 | if (firmware->boot_linux) |
---|
513 | return firmware->boot_linux(kernel_buf, kernel_size, initramfs, |
---|
514 | setup_data, cmdline); |
---|
515 | |
---|
516 | return bios_boot_linux(kernel_buf, kernel_size, initramfs, |
---|
517 | setup_data, cmdline); |
---|
518 | } |
---|