aboutsummaryrefslogtreecommitdiffstats
path: root/extlinux/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'extlinux/main.c')
-rw-r--r--extlinux/main.c127
1 files changed, 70 insertions, 57 deletions
diff --git a/extlinux/main.c b/extlinux/main.c
index 6ce3b605..cf9840dd 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -210,8 +210,8 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs,
}
if (len) {
- set_64(&ex->lba, lba);
- set_16(&ex->len, len);
+ set_64_sl(&ex->lba, lba);
+ set_16_sl(&ex->len, len);
ex++;
}
@@ -225,13 +225,21 @@ static void generate_extents(struct syslinux_extent *ex, int nptrs,
}
if (len) {
- set_64(&ex->lba, lba);
- set_16(&ex->len, len);
+ set_64_sl(&ex->lba, lba);
+ set_16_sl(&ex->len, len);
ex++;
}
}
/*
+ * Form a pointer based on a 16-bit patcharea/epa field
+ */
+static inline void *ptr(void *img, uint16_t *offset_p)
+{
+ return (char *)img + get_16_sl(offset_p);
+}
+
+/*
* Query the device geometry and put it into the boot sector.
* Map the file and put the map in the boot sector and file.
* Stick the "current directory" inode number into the file.
@@ -246,12 +254,12 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
uint64_t totalbytes, totalsectors;
int nsect;
uint32_t *wp;
- struct boot_sector *bs;
+ struct boot_sector *sbs;
struct patch_area *patcharea;
+ struct ext_patch_area *epa;
struct syslinux_extent *ex;
int i, dw, nptrs;
uint32_t csum;
- int secptroffset, diroffset, dirlen, subvoloffset, subvollen;
char *dirpath, *subpath, *xdirpath, *xsubpath;
uint64_t *advptrs;
@@ -310,28 +318,20 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
early bootstrap share code with the FAT version. */
dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
- bs = (struct boot_sector *)boot_block;
+ sbs = (struct boot_sector *)boot_block;
totalsectors = totalbytes >> SECTOR_SHIFT;
if (totalsectors >= 65536) {
- set_16(&bs->bsSectors, 0);
+ set_16(&sbs->bsSectors, 0);
} else {
- set_16(&bs->bsSectors, totalsectors);
+ set_16(&sbs->bsSectors, totalsectors);
}
- set_32(&bs->bsHugeSectors, totalsectors);
+ set_32(&sbs->bsHugeSectors, totalsectors);
- set_16(&bs->bsBytesPerSec, SECTOR_SIZE);
- set_16(&bs->bsSecPerTrack, geo.sectors);
- set_16(&bs->bsHeads, geo.heads);
- set_32(&bs->bsHiddenSecs, geo.start);
-
- /* If we're in RAID mode then patch the appropriate instruction;
- either way write the proper boot signature */
- i = get_16(&bs->bsSignature);
- if (opt.raid_mode)
- set_16((uint16_t *) (boot_block + i), 0x18CD); /* INT 18h */
-
- set_16(&bs->bsSignature, 0xAA55);
+ set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
+ set_16(&sbs->bsSecPerTrack, geo.sectors);
+ set_16(&sbs->bsHeads, geo.heads);
+ set_32(&sbs->bsHiddenSecs, geo.start);
/* Construct the boot file */
@@ -351,27 +351,39 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
*(sectp + i) = BTRFS_EXTLINUX_OFFSET/SECTOR_SIZE + i;
}
- /* First sector need pointer in boot sector */
- set_64(&bs->NextSector, *sectp++);
-
/* Search for LDLINUX_MAGIC to find the patch area */
- for (wp = (uint32_t *) boot_image; get_32(wp) != LDLINUX_MAGIC; wp++) ;
+ for (wp = (uint32_t *) boot_image; get_32_sl(wp) != LDLINUX_MAGIC;
+ wp++)
+ ;
patcharea = (struct patch_area *)wp;
+ epa = ptr(boot_image, &patcharea->epaoffset);
+
+ /* First sector need pointer in boot sector */
+ set_32(ptr(sbs, &epa->sect1ptr0), sectp[0]);
+ set_32(ptr(sbs, &epa->sect1ptr1), sectp[0] >> 32);
+ sectp++;
+
+ /* Handle RAID mode */
+ if (opt.raid_mode) {
+ /* Patch in INT 18h = CD 18 */
+ set_16(ptr(sbs, &epa->raidpatch), 0x18CD);
+ }
/* Set up the totals */
dw = boot_image_len >> 2; /* COMPLETE dwords, excluding ADV */
- set_16(&patcharea->data_sectors, nsect - 2); /* -2 for the ADVs */
- set_16(&patcharea->adv_sectors, 2);
- set_32(&patcharea->dwords, dw);
+ set_16_sl(&patcharea->data_sectors, nsect - 2); /* Not including ADVs */
+ set_16_sl(&patcharea->adv_sectors, 2); /* ADVs need 2 sectors */
+ set_32_sl(&patcharea->dwords, dw);
/* Stupid mode? */
- if (opt.stupid_mode)
- set_16(&patcharea->maxtransfer, 1);
+ if (opt.stupid_mode) {
+ /* Access only one sector at a time */
+ set_16_sl(&patcharea->maxtransfer, 1);
+ }
/* Set the sector extents */
- secptroffset = get_16(&patcharea->secptroffset);
- ex = (struct syslinux_extent *) ((char *)boot_image + secptroffset);
- nptrs = get_16(&patcharea->secptrcnt);
+ ex = ptr(boot_image, &epa->secptroffset);
+ nptrs = get_16_sl(&epa->secptrcnt);
if (nsect > nptrs) {
/* Not necessarily an error in this case, but a general problem */
@@ -383,38 +395,39 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd)
generate_extents(ex, nptrs, sectp, nsect-1-2);
/* ADV pointers */
- advptrs = (uint64_t *)((char *)boot_image +
- get_16(&patcharea->advptroffset));
- set_64(&advptrs[0], sectp[nsect-1-2]);
- set_64(&advptrs[1], sectp[nsect-1-1]);
+ advptrs = ptr(boot_image, &epa->advptroffset);
+ set_64_sl(&advptrs[0], sectp[nsect-1-2]);
+ set_64_sl(&advptrs[1], sectp[nsect-1-1]);
/* Poke in the base directory path */
- diroffset = get_16(&patcharea->diroffset);
- dirlen = get_16(&patcharea->dirlen);
- if (dirlen <= strlen(subpath)) {
- fprintf(stderr, "Subdirectory path too long... aborting install!\n");
- exit(1);
+ if (subpath) {
+ int sublen = strlen(subpath) + 1;
+ if (get_16_sl(&epa->dirlen) < sublen) {
+ fprintf(stderr, "Subdirectory path too long... aborting install!\n");
+ exit(1);
+ }
+ memcpy_to_sl(ptr(boot_image, &epa->diroffset), subpath, sublen);
}
- strncpy((char *)boot_image + diroffset, subpath, dirlen);
free(dirpath);
- /* write subvol info if we have */
- subvoloffset = get_16(&patcharea->subvoloffset);
- subvollen = get_16(&patcharea->subvollen);
- if (subvollen <= strlen(subvol)) {
- fprintf(stderr, "Subvol name too long... aborting install!\n");
- exit(1);
+ /* Poke in the subvolume information */
+ if (1 /* subvol */) {
+ int sublen = strlen(subvol) + 1;
+ if (get_16_sl(&epa->subvollen) < sublen) {
+ fprintf(stderr, "Subvol name too long... aborting install!\n");
+ exit(1);
+ }
+ memcpy_to_sl(ptr(boot_image, &epa->subvoloffset), subvol, sublen);
}
- strncpy((char *)boot_image + subvoloffset, subvol, subvollen);
/* Now produce a checksum */
- set_32(&patcharea->checksum, 0);
+ set_32_sl(&patcharea->checksum, 0);
csum = LDLINUX_MAGIC;
for (i = 0, wp = (uint32_t *) boot_image; i < dw; i++, wp++)
- csum -= get_32(wp); /* Negative checksum */
+ csum -= get_32_sl(wp); /* Negative checksum */
- set_32(&patcharea->checksum, csum);
+ set_32_sl(&patcharea->checksum, csum);
/*
* Assume all bytes modified. This can be optimized at the expense
@@ -490,9 +503,9 @@ int install_bootblock(int fd, const char *device)
return 1;
}
if (fs_type == VFAT) {
- struct boot_sector *bs = (struct boot_sector *)extlinux_bootsect;
- if (xpwrite(fd, &bs->bsHead, bsHeadLen, 0) != bsHeadLen ||
- xpwrite(fd, &bs->bsCode, bsCodeLen,
+ struct boot_sector *sbs = (struct boot_sector *)extlinux_bootsect;
+ if (xpwrite(fd, &sbs->bsHead, bsHeadLen, 0) != bsHeadLen ||
+ xpwrite(fd, &sbs->bsCode, bsCodeLen,
offsetof(struct boot_sector, bsCode)) != bsCodeLen) {
perror("writing fat bootblock");
return 1;