[e16e8f2] | 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: */ |
---|