1 | /* ----------------------------------------------------------------------- * |
---|
2 | * |
---|
3 | * Copyright 2003-2009 H. Peter Anvin - All Rights Reserved |
---|
4 | * Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin |
---|
5 | * Copyright 2010 Shao Miller |
---|
6 | * Copyright 2010-2012 Michal Soltys |
---|
7 | * |
---|
8 | * This program is free software; you can redistribute it and/or modify |
---|
9 | * it under the terms of the GNU General Public License as published by |
---|
10 | * the Free Software Foundation, Inc., 53 Temple Place Ste 330, |
---|
11 | * Boston MA 02111-1307, USA; either version 2 of the License, or |
---|
12 | * (at your option) any later version; incorporated herein by reference. |
---|
13 | * |
---|
14 | * ----------------------------------------------------------------------- */ |
---|
15 | |
---|
16 | /* |
---|
17 | * Please see doc/chain.txt for the detailed documentation. |
---|
18 | */ |
---|
19 | |
---|
20 | #include <com32.h> |
---|
21 | #include <stdlib.h> |
---|
22 | #include <stdio.h> |
---|
23 | #include <ctype.h> |
---|
24 | #include <string.h> |
---|
25 | #include <console.h> |
---|
26 | #include <consoles.h> |
---|
27 | #include <minmax.h> |
---|
28 | #include <stdbool.h> |
---|
29 | #include <dprintf.h> |
---|
30 | #include <errno.h> |
---|
31 | #include <unistd.h> |
---|
32 | #include <syslinux/loadfile.h> |
---|
33 | #include <syslinux/bootrm.h> |
---|
34 | #include <syslinux/config.h> |
---|
35 | #include <syslinux/disk.h> |
---|
36 | #include <syslinux/video.h> |
---|
37 | #include "chain.h" |
---|
38 | #include "utility.h" |
---|
39 | #include "options.h" |
---|
40 | #include "partiter.h" |
---|
41 | #include "mangle.h" |
---|
42 | |
---|
43 | static int fixed_cnt = 128; /* see comments in main() */ |
---|
44 | |
---|
45 | static int overlap(const struct data_area *a, const struct data_area *b) |
---|
46 | { |
---|
47 | return |
---|
48 | a->base + a->size > b->base && |
---|
49 | b->base + b->size > a->base; |
---|
50 | } |
---|
51 | |
---|
52 | static int is_phys(uint8_t sdifs) |
---|
53 | { |
---|
54 | return |
---|
55 | sdifs == SYSLINUX_FS_SYSLINUX || |
---|
56 | sdifs == SYSLINUX_FS_EXTLINUX || |
---|
57 | sdifs == SYSLINUX_FS_ISOLINUX; |
---|
58 | } |
---|
59 | |
---|
60 | /* |
---|
61 | * Search for a specific drive, based on the MBR signature. |
---|
62 | * Return drive and iterator at 0th position. |
---|
63 | */ |
---|
64 | static int find_by_sig(uint32_t mbr_sig, |
---|
65 | struct part_iter **_boot_part) |
---|
66 | { |
---|
67 | struct part_iter *iter = NULL; |
---|
68 | struct disk_info diskinfo; |
---|
69 | int drive; |
---|
70 | |
---|
71 | for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { |
---|
72 | if (disk_get_params(drive, &diskinfo)) |
---|
73 | continue; /* Drive doesn't exist */ |
---|
74 | if (!(iter = pi_begin(&diskinfo, opt.piflags))) |
---|
75 | continue; |
---|
76 | /* Check for a matching MBR disk */ |
---|
77 | if (iter->type == typedos && iter->dos.disk_sig == mbr_sig) |
---|
78 | goto ok; |
---|
79 | pi_del(&iter); |
---|
80 | } |
---|
81 | drive = -1; |
---|
82 | ok: |
---|
83 | *_boot_part = iter; |
---|
84 | return drive; |
---|
85 | } |
---|
86 | |
---|
87 | /* |
---|
88 | * Search for a specific drive/partition, based on the GPT GUID. |
---|
89 | * Return drive and iterator at proper position. |
---|
90 | */ |
---|
91 | static int find_by_guid(const struct guid *gpt_guid, |
---|
92 | struct part_iter **_boot_part) |
---|
93 | { |
---|
94 | struct part_iter *iter = NULL; |
---|
95 | struct disk_info diskinfo; |
---|
96 | int drive; |
---|
97 | |
---|
98 | for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { |
---|
99 | if (disk_get_params(drive, &diskinfo)) |
---|
100 | continue; /* Drive doesn't exist */ |
---|
101 | if (!(iter = pi_begin(&diskinfo, opt.piflags))) |
---|
102 | continue; |
---|
103 | /* Check for a matching GPT disk/partition guid */ |
---|
104 | if (iter->type == typegpt) |
---|
105 | do { |
---|
106 | if (!memcmp(&iter->gpt.part_guid, gpt_guid, sizeof *gpt_guid)) |
---|
107 | goto ok; |
---|
108 | } while (!pi_next(iter)); |
---|
109 | pi_del(&iter); |
---|
110 | } |
---|
111 | drive = -1; |
---|
112 | ok: |
---|
113 | *_boot_part = iter; |
---|
114 | return drive; |
---|
115 | } |
---|
116 | |
---|
117 | /* |
---|
118 | * Search for a specific drive/partition, based on the GPT label. |
---|
119 | * Return drive and iterator at proper position. |
---|
120 | */ |
---|
121 | static int find_by_label(const char *label, struct part_iter **_boot_part) |
---|
122 | { |
---|
123 | struct part_iter *iter = NULL; |
---|
124 | struct disk_info diskinfo; |
---|
125 | int drive; |
---|
126 | |
---|
127 | for (drive = 0x80; drive < 0x80 + fixed_cnt; drive++) { |
---|
128 | if (disk_get_params(drive, &diskinfo)) |
---|
129 | continue; /* Drive doesn't exist */ |
---|
130 | if (!(iter = pi_begin(&diskinfo, opt.piflags))) |
---|
131 | continue; |
---|
132 | /* Check for a matching GPT partition label */ |
---|
133 | if (iter->type == typegpt) |
---|
134 | while (!pi_next(iter)) { |
---|
135 | if (!strcmp(label, iter->gpt.part_label)) |
---|
136 | goto ok; |
---|
137 | } |
---|
138 | pi_del(&iter); |
---|
139 | } |
---|
140 | drive = -1; |
---|
141 | ok: |
---|
142 | *_boot_part = iter; |
---|
143 | return drive; |
---|
144 | } |
---|
145 | |
---|
146 | static void do_boot(struct data_area *data, int ndata) |
---|
147 | { |
---|
148 | struct syslinux_memmap *mmap; |
---|
149 | struct syslinux_movelist *mlist = NULL; |
---|
150 | addr_t endimage; |
---|
151 | uint8_t driveno = opt.regs.edx.b[0]; |
---|
152 | uint8_t swapdrive = driveno & 0x80; |
---|
153 | int i; |
---|
154 | |
---|
155 | mmap = syslinux_memory_map(); |
---|
156 | |
---|
157 | if (!mmap) { |
---|
158 | error("Cannot read system memory map."); |
---|
159 | return; |
---|
160 | } |
---|
161 | |
---|
162 | endimage = 0; |
---|
163 | for (i = 0; i < ndata; i++) { |
---|
164 | if (data[i].base + data[i].size > endimage) |
---|
165 | endimage = data[i].base + data[i].size; |
---|
166 | } |
---|
167 | if (endimage > dosmax) |
---|
168 | goto too_big; |
---|
169 | |
---|
170 | for (i = 0; i < ndata; i++) { |
---|
171 | if (syslinux_add_movelist(&mlist, data[i].base, |
---|
172 | (addr_t) data[i].data, data[i].size)) |
---|
173 | goto enomem; |
---|
174 | } |
---|
175 | |
---|
176 | if (opt.swap && driveno != swapdrive) { |
---|
177 | static const uint8_t swapstub_master[] = { |
---|
178 | /* The actual swap code */ |
---|
179 | 0x53, /* 00: push bx */ |
---|
180 | 0x0f, 0xb6, 0xda, /* 01: movzx bx,dl */ |
---|
181 | 0x2e, 0x8a, 0x57, 0x60, /* 04: mov dl,[cs:bx+0x60] */ |
---|
182 | 0x5b, /* 08: pop bx */ |
---|
183 | 0xea, 0, 0, 0, 0, /* 09: jmp far 0:0 */ |
---|
184 | 0x90, 0x90, /* 0E: nop; nop */ |
---|
185 | /* Code to install this in the right location */ |
---|
186 | /* Entry with DS = CS; ES = SI = 0; CX = 256 */ |
---|
187 | 0x26, 0x66, 0x8b, 0x7c, 0x4c, /* 10: mov edi,[es:si+4*0x13] */ |
---|
188 | 0x66, 0x89, 0x3e, 0x0a, 0x00, /* 15: mov [0x0A],edi */ |
---|
189 | 0x26, 0x8b, 0x3e, 0x13, 0x04, /* 1A: mov di,[es:0x413] */ |
---|
190 | 0x4f, /* 1F: dec di */ |
---|
191 | 0x26, 0x89, 0x3e, 0x13, 0x04, /* 20: mov [es:0x413],di */ |
---|
192 | 0x66, 0xc1, 0xe7, 0x16, /* 25: shl edi,16+6 */ |
---|
193 | 0x26, 0x66, 0x89, 0x7c, 0x4c, /* 29: mov [es:si+4*0x13],edi */ |
---|
194 | 0x66, 0xc1, 0xef, 0x10, /* 2E: shr edi,16 */ |
---|
195 | 0x8e, 0xc7, /* 32: mov es,di */ |
---|
196 | 0x31, 0xff, /* 34: xor di,di */ |
---|
197 | 0xf3, 0x66, 0xa5, /* 36: rep movsd */ |
---|
198 | 0xbe, 0, 0, /* 39: mov si,0 */ |
---|
199 | 0xbf, 0, 0, /* 3C: mov di,0 */ |
---|
200 | 0x8e, 0xde, /* 3F: mov ds,si */ |
---|
201 | 0x8e, 0xc7, /* 41: mov es,di */ |
---|
202 | 0x66, 0xb9, 0, 0, 0, 0, /* 43: mov ecx,0 */ |
---|
203 | 0x66, 0xbe, 0, 0, 0, 0, /* 49: mov esi,0 */ |
---|
204 | 0x66, 0xbf, 0, 0, 0, 0, /* 4F: mov edi,0 */ |
---|
205 | 0xea, 0, 0, 0, 0, /* 55: jmp 0:0 */ |
---|
206 | /* pad out to segment boundary */ |
---|
207 | 0x90, 0x90, /* 5A: ... */ |
---|
208 | 0x90, 0x90, 0x90, 0x90, /* 5C: ... */ |
---|
209 | }; |
---|
210 | static uint8_t swapstub[1024]; |
---|
211 | uint8_t *p; |
---|
212 | |
---|
213 | /* Note: we can't rely on either INT 13h nor the dosmax |
---|
214 | vector to be correct at this stage, so we have to use an |
---|
215 | installer stub to put things in the right place. |
---|
216 | Round the installer location to a 1K boundary so the only |
---|
217 | possible overlap is the identity mapping. */ |
---|
218 | endimage = (endimage + 1023u) & ~1023u; |
---|
219 | |
---|
220 | /* Create swap stub */ |
---|
221 | memcpy(swapstub, swapstub_master, sizeof swapstub_master); |
---|
222 | *(uint16_t *) & swapstub[0x3a] = opt.regs.ds; |
---|
223 | *(uint16_t *) & swapstub[0x3d] = opt.regs.es; |
---|
224 | *(uint32_t *) & swapstub[0x45] = opt.regs.ecx.l; |
---|
225 | *(uint32_t *) & swapstub[0x4b] = opt.regs.esi.l; |
---|
226 | *(uint32_t *) & swapstub[0x51] = opt.regs.edi.l; |
---|
227 | *(uint16_t *) & swapstub[0x56] = opt.regs.ip; |
---|
228 | *(uint16_t *) & swapstub[0x58] = opt.regs.cs; |
---|
229 | p = &swapstub[sizeof swapstub_master]; |
---|
230 | |
---|
231 | /* Mapping table; start out with identity mapping everything */ |
---|
232 | for (i = 0; i < 256; i++) |
---|
233 | p[i] = i; |
---|
234 | |
---|
235 | /* And the actual swap */ |
---|
236 | p[driveno] = swapdrive; |
---|
237 | p[swapdrive] = driveno; |
---|
238 | |
---|
239 | /* Adjust registers */ |
---|
240 | opt.regs.ds = opt.regs.cs = endimage >> 4; |
---|
241 | opt.regs.esi.l = opt.regs.es = 0; |
---|
242 | opt.regs.ecx.l = sizeof swapstub >> 2; |
---|
243 | opt.regs.ip = 0x10; /* Installer offset */ |
---|
244 | opt.regs.ebx.b[0] = opt.regs.edx.b[0] = swapdrive; |
---|
245 | |
---|
246 | if (syslinux_add_movelist(&mlist, endimage, (addr_t) swapstub, |
---|
247 | sizeof swapstub)) |
---|
248 | goto enomem; |
---|
249 | |
---|
250 | endimage += sizeof swapstub; |
---|
251 | } |
---|
252 | |
---|
253 | /* Tell the shuffler not to muck with this area... */ |
---|
254 | syslinux_add_memmap(&mmap, endimage, 0xa0000 - endimage, SMT_RESERVED); |
---|
255 | |
---|
256 | /* Force text mode */ |
---|
257 | syslinux_force_text_mode(); |
---|
258 | |
---|
259 | puts("Booting..."); |
---|
260 | syslinux_shuffle_boot_rm(mlist, mmap, opt.keeppxe, &opt.regs); |
---|
261 | error("Chainboot failed !"); |
---|
262 | return; |
---|
263 | |
---|
264 | too_big: |
---|
265 | error("Loader file too large."); |
---|
266 | return; |
---|
267 | |
---|
268 | enomem: |
---|
269 | error("Out of memory."); |
---|
270 | return; |
---|
271 | } |
---|
272 | |
---|
273 | int find_dp(struct part_iter **_iter) |
---|
274 | { |
---|
275 | struct part_iter *iter = NULL; |
---|
276 | struct disk_info diskinfo; |
---|
277 | struct guid gpt_guid; |
---|
278 | uint64_t fs_lba; |
---|
279 | int drive, hd, partition; |
---|
280 | const union syslinux_derivative_info *sdi; |
---|
281 | |
---|
282 | sdi = syslinux_derivative_info(); |
---|
283 | |
---|
284 | if (!strncmp(opt.drivename, "mbr", 3)) { |
---|
285 | if (find_by_sig(strtoul(opt.drivename + 4, NULL, 0), &iter) < 0) { |
---|
286 | error("Unable to find requested MBR signature."); |
---|
287 | goto bail; |
---|
288 | } |
---|
289 | } else if (!strncmp(opt.drivename, "guid", 4)) { |
---|
290 | if (str_to_guid(opt.drivename + 5, &gpt_guid)) |
---|
291 | goto bail; |
---|
292 | if (find_by_guid(&gpt_guid, &iter) < 0) { |
---|
293 | error("Unable to find requested GPT disk or partition by guid."); |
---|
294 | goto bail; |
---|
295 | } |
---|
296 | } else if (!strncmp(opt.drivename, "label", 5)) { |
---|
297 | if (!opt.drivename[6]) { |
---|
298 | error("No label specified."); |
---|
299 | goto bail; |
---|
300 | } |
---|
301 | if (find_by_label(opt.drivename + 6, &iter) < 0) { |
---|
302 | error("Unable to find requested GPT partition by label."); |
---|
303 | goto bail; |
---|
304 | } |
---|
305 | } else if ((opt.drivename[0] == 'h' || opt.drivename[0] == 'f') && |
---|
306 | opt.drivename[1] == 'd') { |
---|
307 | hd = opt.drivename[0] == 'h' ? 0x80 : 0; |
---|
308 | opt.drivename += 2; |
---|
309 | drive = hd | strtol(opt.drivename, NULL, 0); |
---|
310 | |
---|
311 | if (disk_get_params(drive, &diskinfo)) |
---|
312 | goto bail; |
---|
313 | /* this will start iteration over FDD, possibly raw */ |
---|
314 | if (!(iter = pi_begin(&diskinfo, opt.piflags))) |
---|
315 | goto bail; |
---|
316 | |
---|
317 | } else if (!strcmp(opt.drivename, "boot") || !strcmp(opt.drivename, "fs")) { |
---|
318 | if (!is_phys(sdi->c.filesystem)) { |
---|
319 | error("When syslinux is not booted from physical disk (or its emulation),\n" |
---|
320 | "'boot' and 'fs' are meaningless."); |
---|
321 | goto bail; |
---|
322 | } |
---|
323 | /* offsets match, but in case it changes in the future */ |
---|
324 | if (sdi->c.filesystem == SYSLINUX_FS_ISOLINUX) { |
---|
325 | drive = sdi->iso.drive_number; |
---|
326 | fs_lba = *sdi->iso.partoffset; |
---|
327 | } else { |
---|
328 | drive = sdi->disk.drive_number; |
---|
329 | fs_lba = *sdi->disk.partoffset; |
---|
330 | } |
---|
331 | if (disk_get_params(drive, &diskinfo)) |
---|
332 | goto bail; |
---|
333 | /* this will start iteration over disk emulation, possibly raw */ |
---|
334 | if (!(iter = pi_begin(&diskinfo, opt.piflags))) |
---|
335 | goto bail; |
---|
336 | |
---|
337 | /* 'fs' => we should lookup the syslinux partition number and use it */ |
---|
338 | if (!strcmp(opt.drivename, "fs")) { |
---|
339 | do { |
---|
340 | if (iter->abs_lba == fs_lba) |
---|
341 | break; |
---|
342 | } while (!pi_next(iter)); |
---|
343 | /* broken part structure or other problems */ |
---|
344 | if (iter->status) { |
---|
345 | error("Unable to find partition with syslinux (fs)."); |
---|
346 | goto bail; |
---|
347 | } |
---|
348 | } |
---|
349 | } else { |
---|
350 | error("Unparsable drive specification."); |
---|
351 | goto bail; |
---|
352 | } |
---|
353 | /* main options done - only thing left is explicit partition specification, |
---|
354 | * if we're still at the disk stage with the iterator AND user supplied |
---|
355 | * partition number (including disk pseudo-partition). |
---|
356 | */ |
---|
357 | if (!iter->index && opt.partition) { |
---|
358 | partition = strtol(opt.partition, NULL, 0); |
---|
359 | /* search for matching part#, including disk */ |
---|
360 | do { |
---|
361 | if (iter->index == partition) |
---|
362 | break; |
---|
363 | } while (!pi_next(iter)); |
---|
364 | if (iter->status) { |
---|
365 | error("Unable to find requested disk / partition combination."); |
---|
366 | goto bail; |
---|
367 | } |
---|
368 | } |
---|
369 | |
---|
370 | if (!(iter->di.disk & 0x80) && iter->index) { |
---|
371 | warn("Partitions on floppy devices may not work."); |
---|
372 | } |
---|
373 | |
---|
374 | *_iter = iter; |
---|
375 | |
---|
376 | return 0; |
---|
377 | |
---|
378 | bail: |
---|
379 | pi_del(&iter); |
---|
380 | return -1; |
---|
381 | } |
---|
382 | |
---|
383 | static int setup_handover(const struct part_iter *iter, |
---|
384 | struct data_area *data) |
---|
385 | { |
---|
386 | struct disk_dos_part_entry *ha; |
---|
387 | uint32_t synth_size = sizeof *ha; |
---|
388 | |
---|
389 | /* |
---|
390 | * we have to cover both non-iterated but otherwise properly detected |
---|
391 | * gpt/dos schemes as well as raw disks; checking index for 0 covers both |
---|
392 | */ |
---|
393 | if (iter->index == 0) { |
---|
394 | uint32_t len; |
---|
395 | /* RAW handover protocol */ |
---|
396 | ha = malloc(synth_size); |
---|
397 | if (!ha) { |
---|
398 | critm(); |
---|
399 | goto bail; |
---|
400 | } |
---|
401 | len = ~0u; |
---|
402 | if (iter->length < len) |
---|
403 | len = iter->length; |
---|
404 | lba2chs(&ha->start, &iter->di, 0, L2C_CADD); |
---|
405 | lba2chs(&ha->end, &iter->di, len - 1, L2C_CADD); |
---|
406 | ha->active_flag = 0x80; |
---|
407 | ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */ |
---|
408 | ha->start_lba = 0; |
---|
409 | ha->length = len; |
---|
410 | } else if (iter->type == typegpt) { |
---|
411 | uint32_t *plen; |
---|
412 | /* GPT handover protocol */ |
---|
413 | synth_size += sizeof *plen + iter->gpt.pe_size; |
---|
414 | ha = malloc(synth_size); |
---|
415 | if (!ha) { |
---|
416 | critm(); |
---|
417 | goto bail; |
---|
418 | } |
---|
419 | lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD); |
---|
420 | lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD); |
---|
421 | ha->active_flag = 0x80; |
---|
422 | ha->ostype = 0xED; |
---|
423 | /* All bits set by default */ |
---|
424 | ha->start_lba = ~0u; |
---|
425 | ha->length = ~0u; |
---|
426 | /* If these fit the precision, pass them on */ |
---|
427 | if (iter->abs_lba < ha->start_lba) |
---|
428 | ha->start_lba = iter->abs_lba; |
---|
429 | if (iter->length < ha->length) |
---|
430 | ha->length = iter->length; |
---|
431 | /* Next comes the GPT partition record length */ |
---|
432 | plen = (uint32_t *)(ha + 1); |
---|
433 | plen[0] = iter->gpt.pe_size; |
---|
434 | /* Next comes the GPT partition record copy */ |
---|
435 | memcpy(plen + 1, iter->record, plen[0]); |
---|
436 | #ifdef DEBUG |
---|
437 | dprintf("GPT handover:\n"); |
---|
438 | disk_dos_part_dump(ha); |
---|
439 | disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1)); |
---|
440 | #endif |
---|
441 | /* the only possible case left is dos scheme */ |
---|
442 | } else if (iter->type == typedos) { |
---|
443 | /* MBR handover protocol */ |
---|
444 | ha = malloc(synth_size); |
---|
445 | if (!ha) { |
---|
446 | critm(); |
---|
447 | goto bail; |
---|
448 | } |
---|
449 | memcpy(ha, iter->record, synth_size); |
---|
450 | /* make sure these match bios imaginations and are ebr agnostic */ |
---|
451 | lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD); |
---|
452 | lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD); |
---|
453 | ha->start_lba = iter->abs_lba; |
---|
454 | ha->length = iter->length; |
---|
455 | |
---|
456 | #ifdef DEBUG |
---|
457 | dprintf("MBR handover:\n"); |
---|
458 | disk_dos_part_dump(ha); |
---|
459 | #endif |
---|
460 | } else { |
---|
461 | /* shouldn't ever happen */ |
---|
462 | goto bail; |
---|
463 | } |
---|
464 | |
---|
465 | data->base = 0x7be; |
---|
466 | data->size = synth_size; |
---|
467 | data->data = (void *)ha; |
---|
468 | |
---|
469 | return 0; |
---|
470 | bail: |
---|
471 | return -1; |
---|
472 | } |
---|
473 | |
---|
474 | int main(int argc, char *argv[]) |
---|
475 | { |
---|
476 | struct part_iter *iter = NULL; |
---|
477 | void *sbck = NULL; |
---|
478 | struct data_area fdat, hdat, sdat, data[3]; |
---|
479 | int ndata = 0; |
---|
480 | |
---|
481 | console_ansi_raw(); |
---|
482 | |
---|
483 | memset(&fdat, 0, sizeof fdat); |
---|
484 | memset(&hdat, 0, sizeof hdat); |
---|
485 | memset(&sdat, 0, sizeof sdat); |
---|
486 | |
---|
487 | opt_set_defs(); |
---|
488 | if (opt_parse_args(argc, argv)) |
---|
489 | goto bail; |
---|
490 | |
---|
491 | #if 0 |
---|
492 | /* Get max fixed disk number */ |
---|
493 | fixed_cnt = *(uint8_t *)(0x475); |
---|
494 | |
---|
495 | /* |
---|
496 | * hmm, looks like we can't do that - |
---|
497 | * some bioses/vms just set it to 1 |
---|
498 | * and go on living happily |
---|
499 | * any better options than hardcoded 0x80 - 0xFF ? |
---|
500 | */ |
---|
501 | #endif |
---|
502 | |
---|
503 | /* Get disk/part iterator matching user supplied options */ |
---|
504 | if (find_dp(&iter)) |
---|
505 | goto bail; |
---|
506 | |
---|
507 | /* Perform initial partition entry mangling */ |
---|
508 | if (manglepe_fixchs(iter)) |
---|
509 | goto bail; |
---|
510 | if (manglepe_hide(iter)) |
---|
511 | goto bail; |
---|
512 | |
---|
513 | /* Load the boot file */ |
---|
514 | if (opt.file) { |
---|
515 | fdat.base = (opt.fseg << 4) + opt.foff; |
---|
516 | |
---|
517 | if (loadfile(opt.file, &fdat.data, &fdat.size)) { |
---|
518 | error("Couldn't read the boot file."); |
---|
519 | goto bail; |
---|
520 | } |
---|
521 | if (fdat.base + fdat.size > dosmax) { |
---|
522 | error("The boot file is too big to load at this address."); |
---|
523 | goto bail; |
---|
524 | } |
---|
525 | } |
---|
526 | |
---|
527 | /* Load the sector */ |
---|
528 | if (opt.sect) { |
---|
529 | sdat.base = (opt.sseg << 4) + opt.soff; |
---|
530 | sdat.size = iter->di.bps; |
---|
531 | |
---|
532 | if (sdat.base + sdat.size > dosmax) { |
---|
533 | error("The sector cannot be loaded at such high address."); |
---|
534 | goto bail; |
---|
535 | } |
---|
536 | if (!(sdat.data = disk_read_sectors(&iter->di, iter->abs_lba, 1))) { |
---|
537 | error("Couldn't read the sector."); |
---|
538 | goto bail; |
---|
539 | } |
---|
540 | if (opt.save) { |
---|
541 | if (!(sbck = malloc(sdat.size))) { |
---|
542 | critm(); |
---|
543 | goto bail; |
---|
544 | } |
---|
545 | memcpy(sbck, sdat.data, sdat.size); |
---|
546 | } |
---|
547 | if (opt.file && opt.maps && overlap(&fdat, &sdat)) { |
---|
548 | warn("The sector won't be mmapped, as it would conflict with the boot file."); |
---|
549 | opt.maps = false; |
---|
550 | } |
---|
551 | } |
---|
552 | |
---|
553 | /* Prep the handover */ |
---|
554 | if (opt.hand) { |
---|
555 | if (setup_handover(iter, &hdat)) |
---|
556 | goto bail; |
---|
557 | /* Verify possible conflicts */ |
---|
558 | if ( ( opt.file && overlap(&fdat, &hdat)) || |
---|
559 | ( opt.maps && overlap(&sdat, &hdat)) ) { |
---|
560 | warn("Handover area won't be prepared,\n" |
---|
561 | "as it would conflict with the boot file and/or the sector."); |
---|
562 | opt.hand = false; |
---|
563 | } |
---|
564 | } |
---|
565 | |
---|
566 | /* Adjust registers */ |
---|
567 | |
---|
568 | mangler_init(iter); |
---|
569 | mangler_handover(iter, &hdat); |
---|
570 | mangler_grldr(iter); |
---|
571 | |
---|
572 | /* Patching functions */ |
---|
573 | |
---|
574 | if (manglef_isolinux(&fdat)) |
---|
575 | goto bail; |
---|
576 | |
---|
577 | if (manglef_grub(iter, &fdat)) |
---|
578 | goto bail; |
---|
579 | #if 0 |
---|
580 | if (manglef_drmk(&fdat)) |
---|
581 | goto bail; |
---|
582 | #endif |
---|
583 | if (manglef_bpb(iter, &fdat)) |
---|
584 | goto bail; |
---|
585 | |
---|
586 | if (mangles_bpb(iter, &sdat)) |
---|
587 | goto bail; |
---|
588 | |
---|
589 | if (mangles_save(iter, &sdat, sbck)) |
---|
590 | goto bail; |
---|
591 | |
---|
592 | if (manglesf_bss(&sdat, &fdat)) |
---|
593 | goto bail; |
---|
594 | |
---|
595 | /* This *must* be after BPB saving or copying */ |
---|
596 | if (mangles_cmldr(&sdat)) |
---|
597 | goto bail; |
---|
598 | |
---|
599 | /* |
---|
600 | * Prepare boot-time mmap data. We should to it here, as manglers could |
---|
601 | * potentially alter some of the data. |
---|
602 | */ |
---|
603 | |
---|
604 | if (opt.file) |
---|
605 | memcpy(data + ndata++, &fdat, sizeof fdat); |
---|
606 | if (opt.maps) |
---|
607 | memcpy(data + ndata++, &sdat, sizeof sdat); |
---|
608 | if (opt.hand) |
---|
609 | memcpy(data + ndata++, &hdat, sizeof hdat); |
---|
610 | |
---|
611 | #ifdef DEBUG |
---|
612 | dprintf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n" |
---|
613 | "iter->di C, H, S: %u, %u, %u\n", |
---|
614 | iter->di.disk, iter->di.bps, |
---|
615 | iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt, |
---|
616 | iter->di.cyl, iter->di.head, iter->di.spt); |
---|
617 | dprintf("iter idx: %d\n", iter->index); |
---|
618 | dprintf("iter lba: %"PRIu64"\n", iter->abs_lba); |
---|
619 | if (opt.hand) |
---|
620 | dprintf("hand lba: %u\n", |
---|
621 | ((struct disk_dos_part_entry *)hdat.data)->start_lba); |
---|
622 | #endif |
---|
623 | |
---|
624 | if (opt.warn) { |
---|
625 | puts("Press any key to continue booting..."); |
---|
626 | wait_key(); |
---|
627 | } |
---|
628 | |
---|
629 | if (ndata && !opt.brkchain) /* boot only if we actually chainload */ |
---|
630 | do_boot(data, ndata); |
---|
631 | else |
---|
632 | puts("Service-only run completed, exiting."); |
---|
633 | bail: |
---|
634 | pi_del(&iter); |
---|
635 | /* Free allocated areas */ |
---|
636 | free(fdat.data); |
---|
637 | free(sdat.data); |
---|
638 | free(hdat.data); |
---|
639 | free(sbck); |
---|
640 | return 255; |
---|
641 | } |
---|
642 | |
---|
643 | /* vim: set ts=8 sts=4 sw=4 noet: */ |
---|