/* pi_gpt_ctor() - GPT iterator specific initialization */ static int pi_gpt_ctor(struct part_iter *iter, const struct disk_info *di, int flags, const struct disk_gpt_header *gpth, const struct disk_gpt_part_entry *gptl ) { uint64_t siz; if (pi_ctor(iter, di, flags)) return -1; siz = (uint64_t)gpth->part_count * gpth->part_size; if (!(iter->data = malloc((size_t)siz))) { critm(); goto bail; } memcpy(iter->data, gptl, (size_t)siz); iter->gpt.pe_count = (int)gpth->part_count; iter->gpt.pe_size = (int)gpth->part_size; iter->gpt.ufirst = gpth->lba_first_usable; iter->gpt.ulast = gpth->lba_last_usable; memcpy(&iter->gpt.disk_guid, &gpth->disk_guid, sizeof gpth->disk_guid); memcpy(&iter->gpt.part_guid, &gpth->disk_guid, sizeof gpth->disk_guid); iter->type = typegpt; return 0; bail: pi_dtor_(iter); return -1; }
static struct part_iter *pi_alloc(void) { struct part_iter *iter; if (!(iter = malloc(sizeof *iter))) critm(); else memset(iter, 0, sizeof *iter); return iter; }
/* pi_dos_ctor() - MBR/EBR iterator specific initialization */ static int pi_dos_ctor(struct part_iter *iter, const struct disk_info *di, int flags, const struct disk_dos_mbr *mbr ) { if (pi_ctor(iter, di, flags)) return -1; if (!(iter->data = malloc(sizeof *mbr))) { critm(); goto bail; } memcpy(iter->data, mbr, sizeof *mbr); iter->dos.bebr_index0 = -1; iter->dos.disk_sig = mbr->disk_sig; iter->type = typedos; return 0; bail: pi_dtor_(iter); return -1; }
int main(int argc, char *argv[]) { struct part_iter *iter = NULL; void *sbck = NULL; struct data_area fdat, hdat, sdat, data[3]; int ndata = 0; console_ansi_raw(); memset(&fdat, 0, sizeof fdat); memset(&hdat, 0, sizeof hdat); memset(&sdat, 0, sizeof sdat); opt_set_defs(); if (opt_parse_args(argc, argv)) goto bail; #if 0 /* Get max fixed disk number */ fixed_cnt = *(uint8_t *)(0x475); /* * hmm, looks like we can't do that - * some bioses/vms just set it to 1 * and go on living happily * any better options than hardcoded 0x80 - 0xFF ? */ #endif /* Get disk/part iterator matching user supplied options */ if (find_dp(&iter)) goto bail; /* Perform initial partition entry mangling */ if (manglepe_fixchs(iter)) goto bail; if (manglepe_hide(iter)) goto bail; /* Load the boot file */ if (opt.file) { fdat.base = (opt.fseg << 4) + opt.foff; if (loadfile(opt.file, &fdat.data, &fdat.size)) { error("Couldn't read the boot file."); goto bail; } if (fdat.base + fdat.size > dosmax) { error("The boot file is too big to load at this address."); goto bail; } } /* Load the sector */ if (opt.sect) { sdat.base = (opt.sseg << 4) + opt.soff; sdat.size = iter->di.bps; if (sdat.base + sdat.size > dosmax) { error("The sector cannot be loaded at such high address."); goto bail; } if (!(sdat.data = disk_read_sectors(&iter->di, iter->abs_lba, 1))) { error("Couldn't read the sector."); goto bail; } if (opt.save) { if (!(sbck = malloc(sdat.size))) { critm(); goto bail; } memcpy(sbck, sdat.data, sdat.size); } if (opt.file && opt.maps && overlap(&fdat, &sdat)) { warn("The sector won't be mmapped, as it would conflict with the boot file."); opt.maps = false; } } /* Prep the handover */ if (opt.hand) { if (setup_handover(iter, &hdat)) goto bail; /* Verify possible conflicts */ if ( ( opt.file && overlap(&fdat, &hdat)) || ( opt.maps && overlap(&sdat, &hdat)) ) { warn("Handover area won't be prepared,\n" "as it would conflict with the boot file and/or the sector."); opt.hand = false; } } /* Adjust registers */ mangler_init(iter); mangler_handover(iter, &hdat); mangler_grldr(iter); /* Patching functions */ if (manglef_isolinux(&fdat)) goto bail; if (manglef_grub(iter, &fdat)) goto bail; #if 0 if (manglef_drmk(&fdat)) goto bail; #endif if (manglef_bpb(iter, &fdat)) goto bail; if (mangles_bpb(iter, &sdat)) goto bail; if (mangles_save(iter, &sdat, sbck)) goto bail; if (manglesf_bss(&sdat, &fdat)) goto bail; /* This *must* be after BPB saving or copying */ if (mangles_cmldr(&sdat)) goto bail; /* * Prepare boot-time mmap data. We should to it here, as manglers could * potentially alter some of the data. */ if (opt.file) memcpy(data + ndata++, &fdat, sizeof fdat); if (opt.maps) memcpy(data + ndata++, &sdat, sizeof sdat); if (opt.hand) memcpy(data + ndata++, &hdat, sizeof hdat); #ifdef DEBUG dprintf("iter->di dsk, bps: %X, %u\niter->di lbacnt, C*H*S: %"PRIu64", %u\n" "iter->di C, H, S: %u, %u, %u\n", iter->di.disk, iter->di.bps, iter->di.lbacnt, iter->di.cyl * iter->di.head * iter->di.spt, iter->di.cyl, iter->di.head, iter->di.spt); dprintf("iter idx: %d\n", iter->index); dprintf("iter lba: %"PRIu64"\n", iter->abs_lba); if (opt.hand) dprintf("hand lba: %u\n", ((struct disk_dos_part_entry *)hdat.data)->start_lba); #endif if (opt.warn) { puts("Press any key to continue booting..."); wait_key(); } if (ndata && !opt.brkchain) /* boot only if we actually chainload */ do_boot(data, ndata); else puts("Service-only run completed, exiting."); bail: pi_del(&iter); /* Free allocated areas */ free(fdat.data); free(sdat.data); free(hdat.data); free(sbck); return 255; }
static int setup_handover(const struct part_iter *iter, struct data_area *data) { struct disk_dos_part_entry *ha; uint32_t synth_size = sizeof *ha; /* * we have to cover both non-iterated but otherwise properly detected * gpt/dos schemes as well as raw disks; checking index for 0 covers both */ if (iter->index == 0) { uint32_t len; /* RAW handover protocol */ ha = malloc(synth_size); if (!ha) { critm(); goto bail; } len = ~0u; if (iter->length < len) len = iter->length; lba2chs(&ha->start, &iter->di, 0, L2C_CADD); lba2chs(&ha->end, &iter->di, len - 1, L2C_CADD); ha->active_flag = 0x80; ha->ostype = 0xDA; /* "Non-FS Data", anything is good here though ... */ ha->start_lba = 0; ha->length = len; } else if (iter->type == typegpt) { uint32_t *plen; /* GPT handover protocol */ synth_size += sizeof *plen + iter->gpt.pe_size; ha = malloc(synth_size); if (!ha) { critm(); goto bail; } lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD); lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD); ha->active_flag = 0x80; ha->ostype = 0xED; /* All bits set by default */ ha->start_lba = ~0u; ha->length = ~0u; /* If these fit the precision, pass them on */ if (iter->abs_lba < ha->start_lba) ha->start_lba = iter->abs_lba; if (iter->length < ha->length) ha->length = iter->length; /* Next comes the GPT partition record length */ plen = (uint32_t *)(ha + 1); plen[0] = iter->gpt.pe_size; /* Next comes the GPT partition record copy */ memcpy(plen + 1, iter->record, plen[0]); #ifdef DEBUG dprintf("GPT handover:\n"); disk_dos_part_dump(ha); disk_gpt_part_dump((struct disk_gpt_part_entry *)(plen + 1)); #endif /* the only possible case left is dos scheme */ } else if (iter->type == typedos) { /* MBR handover protocol */ ha = malloc(synth_size); if (!ha) { critm(); goto bail; } memcpy(ha, iter->record, synth_size); /* make sure these match bios imaginations and are ebr agnostic */ lba2chs(&ha->start, &iter->di, iter->abs_lba, L2C_CADD); lba2chs(&ha->end, &iter->di, iter->abs_lba + iter->length - 1, L2C_CADD); ha->start_lba = iter->abs_lba; ha->length = iter->length; #ifdef DEBUG dprintf("MBR handover:\n"); disk_dos_part_dump(ha); #endif } else { /* shouldn't ever happen */ goto bail; } data->base = 0x7be; data->size = synth_size; data->data = (void *)ha; return 0; bail: return -1; }