static int write_stage2(ig_data_t *install) { ig_device_t *device = &install->device; ig_stage2_t *stage2 = &install->stage2; off_t offset; assert(install != NULL); if (is_bootpar(device->type)) { /* * stage2 is already on the filesystem, we only need to update * the first two blocks (that we have modified during * prepare_stage2()) */ if (write_out(device->part_fd, stage2->file, SECTOR_SIZE, stage2->pcfs_first_sectors[0] * SECTOR_SIZE) != BC_SUCCESS || write_out(device->part_fd, stage2->file + SECTOR_SIZE, SECTOR_SIZE, stage2->pcfs_first_sectors[1] * SECTOR_SIZE) != BC_SUCCESS) { (void) fprintf(stderr, WRITE_FAIL_STAGE2); return (BC_ERROR); } (void) fprintf(stdout, WRITE_STAGE2_PCFS); return (BC_SUCCESS); } /* * For disk, write stage2 starting at STAGE2_BLKOFF sector. * Note that we use stage2->buf rather than stage2->file, because we * may have extended information after the latter. * * If we're writing to an EFI-labeled disk where stage2 lives in the * 3.5MB boot loader gap following the ZFS vdev labels, make sure the * size of the buffer doesn't exceed the size of the gap. */ if (is_efi(device->type) && stage2->buf_size > STAGE2_MAXSIZE) { (void) fprintf(stderr, WRITE_FAIL_STAGE2); return (BC_ERROR); } offset = STAGE2_BLKOFF(device->type) * SECTOR_SIZE; if (write_out(device->part_fd, stage2->buf, stage2->buf_size, offset) != BC_SUCCESS) { perror("write"); return (BC_ERROR); } /* Simulate the "old" installgrub output. */ (void) fprintf(stdout, WRITE_STAGE2_DISK, device->partition, (stage2->buf_size / SECTOR_SIZE) + 1, STAGE2_BLKOFF(device->type), stage2->first_sector); return (BC_SUCCESS); }
static void install_int18_hack(void) { static const uint8_t int18_hack[] = { 0xcd, 0x18, /* int $0x18 */ 0xea, 0xf0, 0xff, 0x00, 0xf0, /* ljmpw $0xf000,$0xfff0 */ 0xf4 /* hlt */ }; uint16_t *retcode; retcode = GET_PTR(*(far_ptr_t *)((char *)GET_PTR(InitStack) + 44)); /* Don't do this if the return already points to int $0x18 */ if (*retcode != 0x18cd) { uint32_t efi_ptr; bool efi = false; for (efi_ptr = 0xe0000 ; efi_ptr < 0x100000 ; efi_ptr += 16) { if (is_efi((const struct efi_struct *)efi_ptr)) { efi = true; break; } } if (efi) { uint8_t *src = GET_PTR(InitStack); uint8_t *dst = src - sizeof int18_hack; memmove(dst, src, 52); memcpy(dst+52, int18_hack, sizeof int18_hack); InitStack.offs -= sizeof int18_hack; /* Clobber the return address */ *(uint16_t *)(dst+44) = OFFS_WRT(dst+52, InitStack.seg); *(uint16_t *)(dst+46) = InitStack.seg; } } }
static int get_start_sector(ig_device_t *device) { uint32_t secnum = 0, numsec = 0; int i, pno, rval, log_part = 0; struct mboot *mboot; struct ipart *part; ext_part_t *epp; struct part_info dkpi; struct extpart_info edkpi; if (is_efi(device->type)) { struct dk_gpt *vtoc; if (efi_alloc_and_read(device->disk_fd, &vtoc) < 0) return (BC_ERROR); device->start_sector = vtoc->efi_parts[device->slice].p_start; /* GPT doesn't use traditional slice letters */ device->slice = 0xff; device->partition = 0; efi_free(vtoc); goto found_part; } mboot = (struct mboot *)device->boot_sector; if (is_bootpar(device->type)) { if (find_x86_bootpar(mboot, &pno, &secnum) != BC_SUCCESS) { (void) fprintf(stderr, NOBOOTPAR); return (BC_ERROR); } else { device->start_sector = secnum; device->partition = pno; goto found_part; } } /* * Search for Solaris fdisk partition * Get the solaris partition information from the device * and compare the offset of S2 with offset of solaris partition * from fdisk partition table. */ if (ioctl(device->part_fd, DKIOCEXTPARTINFO, &edkpi) < 0) { if (ioctl(device->part_fd, DKIOCPARTINFO, &dkpi) < 0) { (void) fprintf(stderr, PART_FAIL); return (BC_ERROR); } else { edkpi.p_start = dkpi.p_start; } } for (i = 0; i < FD_NUMPART; i++) { part = (struct ipart *)mboot->parts + i; if (part->relsect == 0) { (void) fprintf(stderr, BAD_PART, i); return (BC_ERROR); } if (edkpi.p_start >= part->relsect && edkpi.p_start < (part->relsect + part->numsect)) { /* Found the partition */ break; } } if (i == FD_NUMPART) { /* No solaris fdisk partitions (primary or logical) */ (void) fprintf(stderr, NOSOLPAR); return (BC_ERROR); } /* * We have found a Solaris fdisk partition (primary or extended) * Handle the simple case first: Solaris in a primary partition */ if (!fdisk_is_dos_extended(part->systid)) { device->start_sector = part->relsect; device->partition = i; goto found_part; } /* * Solaris in a logical partition. Find that partition in the * extended part. */ if ((rval = libfdisk_init(&epp, device->path_p0, NULL, FDISK_READ_DISK)) != FDISK_SUCCESS) { switch (rval) { /* * The first 3 cases are not an error per-se, just that * there is no Solaris logical partition */ case FDISK_EBADLOGDRIVE: case FDISK_ENOLOGDRIVE: case FDISK_EBADMAGIC: (void) fprintf(stderr, NOSOLPAR); return (BC_ERROR); case FDISK_ENOVGEOM: (void) fprintf(stderr, NO_VIRT_GEOM); return (BC_ERROR); case FDISK_ENOPGEOM: (void) fprintf(stderr, NO_PHYS_GEOM); return (BC_ERROR); case FDISK_ENOLGEOM: (void) fprintf(stderr, NO_LABEL_GEOM); return (BC_ERROR); default: (void) fprintf(stderr, LIBFDISK_INIT_FAIL); return (BC_ERROR); } } rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); libfdisk_fini(&epp); if (rval != FDISK_SUCCESS) { /* No solaris logical partition */ (void) fprintf(stderr, NOSOLPAR); return (BC_ERROR); } device->start_sector = secnum; device->partition = pno - 1; log_part = 1; found_part: /* get confirmation for -m */ if (write_mbr && !force_mbr) { (void) fprintf(stdout, MBOOT_PROMPT); if (!yes()) { write_mbr = 0; (void) fprintf(stdout, MBOOT_NOT_UPDATED); return (BC_ERROR); } } /* * Currently if Solaris is in an extended partition we need to * write GRUB to the MBR. Check for this. */ if (log_part && !write_mbr) { (void) fprintf(stdout, gettext("Installing Solaris on an " "extended partition... forcing MBR update\n")); write_mbr = 1; } /* * warn, if Solaris in primary partition and GRUB not in MBR and * partition is not active */ if (!log_part && part->bootid != 128 && !write_mbr) { (void) fprintf(stdout, SOLPAR_INACTIVE, device->partition + 1); } return (BC_SUCCESS); }
/* * open the device and fill the various members of ig_device_t. */ static int init_device(ig_device_t *device, char *path) { struct dk_gpt *vtoc; fstyp_handle_t fhdl; const char *fident; bzero(device, sizeof (*device)); device->part_fd = -1; device->disk_fd = -1; device->path_p0 = NULL; device->path = strdup(path); if (device->path == NULL) { perror(gettext("Memory allocation failed")); return (BC_ERROR); } if (strstr(device->path, "diskette")) { (void) fprintf(stderr, gettext("installing GRUB to a floppy " "disk is no longer supported\n")); return (BC_ERROR); } /* Detect if the target device is a pcfs partition. */ if (strstr(device->path, "p0:boot")) device->type = IG_DEV_X86BOOTPAR; if (get_disk_fd(device) != BC_SUCCESS) return (BC_ERROR); /* read in the device boot sector. */ if (read(device->disk_fd, device->boot_sector, SECTOR_SIZE) != SECTOR_SIZE) { (void) fprintf(stderr, gettext("Error reading boot sector\n")); perror("read"); return (BC_ERROR); } if (efi_alloc_and_read(device->disk_fd, &vtoc) >= 0) { device->type = IG_DEV_EFI; efi_free(vtoc); } if (get_raw_partition_fd(device) != BC_SUCCESS) return (BC_ERROR); if (is_efi(device->type)) { if (fstyp_init(device->part_fd, 0, NULL, &fhdl) != 0) return (BC_ERROR); if (fstyp_ident(fhdl, "zfs", &fident) != 0) { fstyp_fini(fhdl); (void) fprintf(stderr, gettext("Booting of EFI labeled " "disks is only supported with ZFS\n")); return (BC_ERROR); } fstyp_fini(fhdl); } if (get_start_sector(device) != BC_SUCCESS) return (BC_ERROR); return (BC_SUCCESS); }