static int read_sector(mbr_args_t *a, uint sector, int count) { int error; error = disk_read_sectors(a->strat, a->lp, a->bp, sector, count); if (error != 0) a->error = error; return error; }
static struct disk_gpt_header *try_gpt_hdr(const struct disk_info *di, int sec) { const char *desc = sec ? "backup" : "primary"; uint64_t gpt_cur = sec ? di->lbacnt - 1 : 1; struct disk_gpt_header *gpth; char errbuf[64]; gpth = disk_read_sectors(di, gpt_cur, 1); if (!gpth) { sprintf(errbuf, "Unable to read %s GPT header.", desc); try_gpt_we(errbuf, sec); return NULL; } if(!valid_crc_hdr(gpth)) { sprintf(errbuf, "Invalid checksum of %s GPT header.", desc); try_gpt_we(errbuf, sec); free(gpth); return NULL; } return gpth; }
static struct disk_gpt_part_entry *try_gpt_list(const struct disk_info *di, const struct disk_gpt_header *gpth, int alt) { int pri = gpth->lba_cur < gpth->lba_alt; const char *desc = alt ? "alternative" : "main"; struct disk_gpt_part_entry *gptl; char errbuf[64]; uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ uint64_t gpt_loff; /* offset to GPT partition list in sectors */ gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; if (!alt) { /* prefer header value for partition table if not asking for alternative */ gpt_loff = gpth->lba_table; } else { /* try to read alternative, we have to calculate its position */ if (!pri) gpt_loff = gpth->lba_alt + 1; else gpt_loff = gpth->lba_alt - gpt_lcnt; } gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt); if (!gptl) { sprintf(errbuf, "Unable to read %s GPT partition list.", desc); try_gpt_we(errbuf, alt); return NULL; } if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) { sprintf(errbuf, "Invalid checksum of %s GPT partition list.", desc); try_gpt_we(errbuf, alt); free(gptl); return NULL; } return gptl; }
/** * pi_begin() - check disk, validate, and get proper iterator * @di: diskinfo struct pointer * * This function checks the disk for GPT or legacy partition table and allocates * an appropriate iterator. **/ struct part_iter *pi_begin(const struct disk_info *di, int stepall) { int setraw = 0; struct part_iter *iter = NULL; struct disk_dos_mbr *mbr = NULL; struct disk_gpt_header *gpth = NULL; struct disk_gpt_part_entry *gptl = NULL; /* Read MBR */ if (!(mbr = disk_read_sectors(di, 0, 1))) { error("Couldn't read first disk sector.\n"); goto bail; } setraw = -1; /* Check for MBR magic*/ if (mbr->sig != disk_mbr_sig_magic) { error("No MBR magic.\n"); goto bail; } /* Check for GPT protective MBR */ if (mbr->table[0].ostype == 0xEE) { if (!(gpth = disk_read_sectors(di, 1, 1))) { error("Couldn't read potential GPT header.\n"); goto bail; } } if (gpth && gpth->rev.uint32 == 0x00010000 && !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof(disk_gpt_sig_magic))) { /* looks like GPT v1.0 */ uint64_t gpt_loff; /* offset to GPT partition list in sectors */ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ #ifdef DEBUG puts("Looks like a GPT v1.0 disk."); disk_gpt_header_dump(gpth); #endif /* Verify checksum, fallback to backup, then bail if invalid */ if (gpt_check_hdr_crc(di, &gpth)) goto bail; gpt_loff = gpth->lba_table; gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; /* * disk_read_sectors allows reading of max 255 sectors, so we use * it as a sanity check base. EFI doesn't specify max (AFAIK). * Apart from that, some extensive sanity checks. */ if (!gpt_loff || !gpt_lsiz || gpt_lcnt > 255u || gpth->lba_first_usable > gpth->lba_last_usable || !sane(gpt_loff, gpt_lcnt) || gpt_loff + gpt_lcnt > gpth->lba_first_usable || !sane(gpth->lba_last_usable, gpt_lcnt) || gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt || gpth->lba_alt >= di->lbacnt || gpth->part_size < sizeof(struct disk_gpt_part_entry)) { error("Invalid GPT header's values.\n"); goto bail; } if (!(gptl = disk_read_sectors(di, gpt_loff, (uint8_t)gpt_lcnt))) { error("Couldn't read GPT partition list.\n"); goto bail; } /* Check array checksum(s). */ if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { error("WARNING: GPT partition list checksum invalid, trying backup.\n"); free(gptl); /* secondary array directly precedes secondary header */ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, (uint8_t)gpt_lcnt))) { error("Couldn't read backup GPT partition list.\n"); goto bail; } if (check_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { error("Backup GPT partition list checksum invalid.\n"); goto bail; } } /* allocate iterator and exit */ iter = pi_new(typegpt, di, stepall, gpth, gptl); } else { /* looks like MBR */ iter = pi_new(typedos, di, stepall, mbr); } setraw = 0; bail: if (setraw) { error("WARNING: treating disk as raw.\n"); iter = pi_new(typeraw, di, stepall); } free(mbr); free(gpth); free(gptl); return iter; }
const char * convertdisklabel(struct disklabel *lp, void (*strat)(struct buf *), struct buf *bp, uint32_t secperunit) { struct partition rp, *altp, *p; int geom_ok; const char *str; memset(&rp, 0, sizeof(rp)); rp.p_size = secperunit; rp.p_fstype = FS_UNUSED; /* If we can seek to d_secperunit - 1, believe the disk geometry. */ if (secperunit != 0 && disk_read_sectors(strat, lp, bp, secperunit - 1, 1) == 0) geom_ok = 1; else geom_ok = 0; #if 0 printf("%s: secperunit (%" PRIu32 ") %s\n", __func__, secperunit, geom_ok ? "ok" : "not ok"); #endif p = &lp->d_partitions[RAW_PART]; if (RAW_PART == 'c' - 'a') altp = &lp->d_partitions['d' - 'a']; else altp = &lp->d_partitions['c' - 'a']; if (lp->d_npartitions > RAW_PART && p->p_offset == 0 && p->p_size != 0) return NULL; /* already a raw partition */ else if (lp->d_npartitions > MAX('c', 'd') - 'a' && altp->p_offset == 0 && altp->p_size != 0) { /* alternate partition ('c' or 'd') is suitable for raw slot, * swap with 'd' or 'c'. */ rp = *p; *p = *altp; *altp = rp; return NULL; } else if (lp->d_npartitions <= RAW_PART && lp->d_npartitions > 'c' - 'a') { /* No raw partition is present, but the alternate is present. * Copy alternate to raw partition. */ lp->d_npartitions = RAW_PART + 1; *p = *altp; return NULL; } else if (!geom_ok) str = "no raw partition and disk reports bad geometry"; else if (lp->d_npartitions <= RAW_PART) { memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(struct partition) * (RAW_PART - lp->d_npartitions)); *p = rp; lp->d_npartitions = RAW_PART + 1; return NULL; } else if (lp->d_npartitions < MAXPARTITIONS) { memmove(p + 1, p, sizeof(struct partition) * (lp->d_npartitions - RAW_PART)); *p = rp; lp->d_npartitions++; return NULL; } else str = "no raw partition and partition table is full"; #ifdef DIAGNOSTIC printf("Bad partition: %s\n", str); printf("type = %u, subtype = %u, typename = %s\n", lp->d_type, lp->d_subtype, lp->d_typename); printf("secsize = %u, nsectors = %u, ntracks = %u\n", lp->d_secsize, lp->d_nsectors, lp->d_ntracks); printf("ncylinders = %u, secpercyl = %u, secperunit = %u\n", lp->d_ncylinders, lp->d_secpercyl, lp->d_secperunit); printf("npartitions = %u\n", lp->d_npartitions); for (size_t i = 0; i < MIN(lp->d_npartitions, MAXPARTITIONS); i++) { p = &lp->d_partitions[i]; printf("\t%c: offset = %u size = %u fstype = %u\n", (char)(i + 'a'), p->p_offset, p->p_size, p->p_fstype); } #endif return str; }
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; }
/* pi_begin() - validate and and get proper iterator for a disk described by di */ struct part_iter *pi_begin(const struct disk_info *di, int flags) { int gptprot, ret = -1; struct part_iter *iter; struct disk_dos_mbr *mbr = NULL; struct disk_gpt_header *gpth = NULL; struct disk_gpt_part_entry *gptl = NULL; /* Preallocate iterator */ if (!(iter = pi_alloc())) goto bail; /* Read MBR */ if (!(mbr = disk_read_sectors(di, 0, 1))) { error("Couldn't read the first disk sector."); goto bail; } /* Check for MBR magic */ if (mbr->sig != disk_mbr_sig_magic) { warn("No MBR magic, treating disk as raw."); /* looks like RAW */ ret = pi_ctor(iter, di, flags); goto bail; } /* Check for GPT protective MBR */ gptprot = 0; for (size_t i = 0; i < 4; i++) gptprot |= (mbr->table[i].ostype == 0xEE); if (gptprot && !(flags & PIF_PREFMBR)) { if (!(gpth = disk_read_sectors(di, 1, 1))) { error("Couldn't read potential GPT header."); goto bail; } } if (gpth && gpth->rev.uint32 == 0x00010000 && !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) { /* looks like GPT v1.0 */ uint64_t gpt_loff; /* offset to GPT partition list in sectors */ uint64_t gpt_lsiz; /* size of GPT partition list in bytes */ uint64_t gpt_lcnt; /* size of GPT partition in sectors */ #ifdef DEBUG dprintf("Looks like a GPT v1.0 disk.\n"); disk_gpt_header_dump(gpth); #endif /* Verify checksum, fallback to backup, then bail if invalid */ if (gpt_check_hdr_crc(di, &gpth)) goto bail; gpt_loff = gpth->lba_table; gpt_lsiz = (uint64_t)gpth->part_size * gpth->part_count; gpt_lcnt = (gpt_lsiz + di->bps - 1) / di->bps; /* * disk_read_sectors allows reading of max 255 sectors, so we use * it as a sanity check base. EFI doesn't specify max (AFAIK). * Apart from that, some extensive sanity checks. */ if (!(flags & PIF_RELAX) && ( !gpt_loff || !gpt_lsiz || gpt_lcnt > 255u || gpth->lba_first_usable > gpth->lba_last_usable || !sane(gpt_loff, gpt_lcnt) || gpt_loff + gpt_lcnt > gpth->lba_first_usable || !sane(gpth->lba_last_usable, gpt_lcnt) || gpth->lba_last_usable + gpt_lcnt >= gpth->lba_alt || gpth->lba_alt >= di->lbacnt || gpth->part_size < sizeof *gptl)) { error("Invalid GPT header's values."); goto bail; } if (!(gptl = disk_read_sectors(di, gpt_loff, gpt_lcnt))) { error("Couldn't read GPT partition list."); goto bail; } /* Check array checksum(s). */ if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, (unsigned int)gpt_lsiz)) { warn("Checksum of the main GPT partition list is invalid, trying backup."); free(gptl); /* secondary array directly precedes secondary header */ if (!(gptl = disk_read_sectors(di, gpth->lba_alt - gpt_lcnt, gpt_lcnt))) { error("Couldn't read backup GPT partition list."); goto bail; } if (!valid_crc(gpth->table_chksum, (const uint8_t *)gptl, gpt_lsiz)) { error("Checksum of the backup GPT partition list is invalid, giving up."); goto bail; } } /* looks like GPT */ ret = pi_gpt_ctor(iter, di, flags, gpth, gptl); } else { /* looks like MBR */ ret = pi_dos_ctor(iter, di, flags, mbr); } bail: if (ret < 0) free(iter); free(mbr); free(gpth); free(gptl); return iter; }
/* * Attempt to read a disk label from a device * using the indicated strategy routine. * The label must be partly set up before this: * secpercyl and anything required in the strategy routine * (e.g., sector size) must be filled in before calling us. * Returns null on success and an error string on failure. */ const char * readdisklabel(dev_t dev, void (*strat)(struct buf *), struct disklabel *lp, struct cpu_disklabel *clp) { struct buf *bp; struct disklabel *dlp; struct dkbad *bdp; const char *msg = NULL; uint32_t secperunit; int i; /* minimal requirements for archtypal disk label */ if (lp->d_secsize == 0) lp->d_secsize = DEV_BSIZE; if (lp->d_secperunit == 0) lp->d_secperunit = 0x1fffffff; lp->d_npartitions = RAW_PART + 1; if (lp->d_partitions[RAW_PART].p_size == 0) lp->d_partitions[RAW_PART].p_size = lp->d_secperunit; lp->d_partitions[RAW_PART].p_offset = 0; secperunit = lp->d_secperunit; /* obtain buffer to probe drive with */ bp = geteblk((int)lp->d_secsize); bp->b_dev = dev; /* Next, dig out disk label. If successful, locate disk * label within block and validate. */ if (disk_read_sectors(strat, lp, bp, LABELSECTOR, 1) != 0) { msg = "disk label read error"; goto done; } for (dlp = (struct disklabel *)bp->b_data; dlp <= (struct disklabel *)((char *)bp->b_data + lp->d_secsize - sizeof(*dlp)); dlp = (struct disklabel *)((char *)dlp + sizeof(long))) { if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) { if (msg == NULL) msg = "no disk label"; } else if (dlp->d_npartitions > MAXPARTITIONS || dkcksum(dlp) != 0) msg = "disk label corrupted"; else { *lp = *dlp; msg = NULL; break; } } if (msg) goto done; if ((msg = convertdisklabel(lp, strat, bp, secperunit)) != NULL) goto done; /* obtain bad sector table if requested and present */ if (clp && (bdp = &clp->bad) != NULL && (lp->d_flags & D_BADSECT)) { struct dkbad *db; i = 0; do { /* read a bad sector table */ bp->b_oflags &= ~(BO_DONE); bp->b_flags |= B_READ; bp->b_blkno = lp->d_secperunit - lp->d_nsectors + i; if (lp->d_secsize > DEV_BSIZE) bp->b_blkno *= lp->d_secsize / DEV_BSIZE; else bp->b_blkno /= DEV_BSIZE / lp->d_secsize; bp->b_bcount = lp->d_secsize; bp->b_cylinder = lp->d_ncylinders - 1; (*strat)(bp); /* if successful, validate, otherwise try another */ if (biowait(bp)) { msg = "bad sector table I/O error"; } else { db = (struct dkbad *)(bp->b_data); #define DKBAD_MAGIC 0x4321 if (db->bt_mbz == 0 && db->bt_flag == DKBAD_MAGIC) { msg = NULL; *bdp = *db; break; } else msg = "bad sector table corrupted"; } } while (bp->b_error != 0 && (i += 2) < 10 && i < lp->d_nsectors); } done: brelse(bp, 0); return (msg); }
/* pi_begin() - validate and and get proper iterator for a disk described by di */ struct part_iter *pi_begin(const struct disk_info *di, int flags) { int isgpt = 0, ret = -1; struct part_iter *iter; struct disk_dos_mbr *mbr = NULL; struct disk_gpt_header *gpth = NULL; struct disk_gpt_part_entry *gptl = NULL; /* Preallocate iterator */ if (!(iter = pi_alloc())) goto out; /* Read MBR */ if (!(mbr = disk_read_sectors(di, 0, 1))) { error("Unable to read the first disk sector."); goto out; } /* Check for MBR magic */ if (mbr->sig != disk_mbr_sig_magic) { warn("No MBR magic, treating disk as raw."); /* looks like RAW */ ret = pi_ctor(iter, di, flags); goto out; } /* Check for GPT protective MBR */ for (size_t i = 0; i < 4; i++) isgpt |= (mbr->table[i].ostype == 0xEE); isgpt = isgpt && !(flags & PIF_PREFMBR); /* Try to read GPT header */ if (isgpt) { gpth = try_gpt_hdr(di, 0); if (!gpth) /* * this read might fail if bios reports different disk size (different vm/pc) * not much we can do here to avoid it */ gpth = try_gpt_hdr(di, 1); if (!gpth) goto out; } if (gpth && gpth->rev.uint32 == 0x00010000 && !memcmp(gpth->sig, disk_gpt_sig_magic, sizeof gpth->sig)) { /* looks like GPT v1.0 */ #ifdef DEBUG dprintf("Looks like a GPT v1.0 disk.\n"); disk_gpt_header_dump(gpth); #endif if (notsane_gpt_hdr(di, gpth, flags)) { error("GPT header values are corrupted."); goto out; } gptl = try_gpt_list(di, gpth, 0); if (!gptl) gptl = try_gpt_list(di, gpth, 1); if (!gptl) goto out; /* looks like GPT */ ret = pi_gpt_ctor(iter, di, flags, gpth, gptl); } else { /* looks like MBR */ ret = pi_dos_ctor(iter, di, flags, mbr); } out: if (ret < 0) { free(iter); iter = NULL; } free(mbr); free(gpth); free(gptl); return iter; }
const char * convertdisklabel(struct disklabel *lp, void (*strat)(struct buf *), struct buf *bp, uint32_t secperunit) { struct partition rp, *altp, *p; int geom_ok; memset(&rp, 0, sizeof(rp)); rp.p_size = secperunit; rp.p_fstype = FS_UNUSED; /* If we can seek to d_secperunit - 1, believe the disk geometry. */ if (secperunit != 0 && disk_read_sectors(strat, lp, bp, secperunit - 1, 1) == 0) geom_ok = 1; else geom_ok = 0; #if 0 printf("%s: secperunit (%" PRIu32 ") %s\n", __func__, secperunit, geom_ok ? "ok" : "not ok"); #endif p = &lp->d_partitions[RAW_PART]; if (RAW_PART == 'c' - 'a') altp = &lp->d_partitions['d' - 'a']; else altp = &lp->d_partitions['c' - 'a']; if (lp->d_npartitions > RAW_PART && p->p_offset == 0 && p->p_size != 0) ; /* already a raw partition */ else if (lp->d_npartitions > MAX('c', 'd') - 'a' && altp->p_offset == 0 && altp->p_size != 0) { /* alternate partition ('c' or 'd') is suitable for raw slot, * swap with 'd' or 'c'. */ rp = *p; *p = *altp; *altp = rp; } else if (lp->d_npartitions <= RAW_PART && lp->d_npartitions > 'c' - 'a') { /* No raw partition is present, but the alternate is present. * Copy alternate to raw partition. */ lp->d_npartitions = RAW_PART + 1; *p = *altp; } else if (!geom_ok) return "no raw partition and disk reports bad geometry"; else if (lp->d_npartitions <= RAW_PART) { memset(&lp->d_partitions[lp->d_npartitions], 0, sizeof(struct partition) * (RAW_PART - lp->d_npartitions)); *p = rp; lp->d_npartitions = RAW_PART + 1; } else if (lp->d_npartitions < MAXPARTITIONS) { memmove(p + 1, p, sizeof(struct partition) * (lp->d_npartitions - RAW_PART)); *p = rp; lp->d_npartitions++; } else return "no raw partition and partition table is full"; return NULL; }
ssize_t hd_read(minor_t minor, lbaint_t lba_start, lbaint_t count, void* buffer) { ssize_t read = 0; CHS_t chs_addr_start; chs_disk_geometry_t* dev_info = (chs_disk_geometry_t*) hd_getinfo(minor); assert(dev_info != NULL); // check that the number of sectors per track is not greated than what I can write in a real mode segment assert(dev_info->NS <= (SEGMENT_SIZE_16bit_MODE / SECTOR_SIZE)); // check parameters assert(lba_start < dev_info->Nlba); assert(lba_start + count <= dev_info->Nlba); uint16_t buf_rm_segment; uint16_t buf_rm_offset; #ifdef BOOTLOADER_PROTECTED_MODE_ENABLED buf_rm_segment = SEGMENT_EXTRA_DATA_RM; buf_rm_offset = 0x0000; #else reg_get_data_segment(&buf_rm_segment); buf_rm_offset = (uint16_t)(uint32_t)buffer; #endif uint8_t nb_sectors_to_read = count; while (count > 0) { // convert LBA address to CHS address lbatochs(dev_info, lba_start, &chs_addr_start); #ifdef DEBUG_HD_DRIVER debug_printf("hd(%u,%u): req READ (lba_start = %u <=> CHS=(%u,%u,%u), count = %u)\r\n", HARD_DISK_DRIVER, minor, lba_start, chs_addr_start.C, chs_addr_start.H, chs_addr_start.S, count); #endif // check track bounds if (count > dev_info->NS) { nb_sectors_to_read = dev_info->NS - chs_addr_start.S + 1; #ifdef DEBUG_HD_DRIVER debug_printf("hd(%u,%u): resize req to (lba_start = %u, count = %u)\r\n", HARD_DISK_DRIVER, minor, lba_start, nb_sectors_to_read); #endif } #ifdef DEBUG_HD_DRIVER debug_printf("hd(%u,%u): [bios] disk %#02x, attempt to read %u sectors", HARD_DISK_DRIVER, minor, BIOS_HD_DRIVE_BASE_NB + minor, nb_sectors_to_read); #endif uint8_t nb_read_sectors = 0; for (uint8_t i=0; i<5 && (nb_read_sectors != nb_sectors_to_read); i++) { nb_read_sectors = disk_read_sectors(BIOS_HD_DRIVE_BASE_NB + minor, buf_rm_segment, buf_rm_offset, &chs_addr_start, nb_sectors_to_read); } #ifdef DEBUG_HD_DRIVER if (nb_read_sectors != nb_sectors_to_read) { debug_printf(", read %u sectors [NOK]\r\n", nb_read_sectors); } else { debug_printf(" [OK]\r\n"); } #endif size_t nb_read_bytes = nb_read_sectors * SECTOR_SIZE; #ifdef BOOTLOADER_PROTECTED_MODE_ENABLED // copy data to buffer memcpy(buffer, (void*)(buf_rm_segment << 4 | buf_rm_offset), nb_read_bytes); buf_rm_offset = 0x0000; #else buf_rm_offset += nb_read_bytes; #endif read += nb_read_bytes; count -= nb_read_sectors; lba_start += nb_read_sectors; } return read; }