aboutsummaryrefslogtreecommitdiffstats
path: root/extlinux
diff options
context:
space:
mode:
authorhpa <hpa>2004-12-20 02:30:38 +0000
committerhpa <hpa>2004-12-20 02:30:38 +0000
commit44d32d4cd477a5595debb69bc7154923ac530433 (patch)
tree2cad1410f6731de350189bf1879e9e7b3fb1bc96 /extlinux
parent24e644726fb0fea76bb6db2f25f5343b257e950c (diff)
downloadsyslinux-elf-44d32d4cd477a5595debb69bc7154923ac530433.tar.gz
syslinux-elf-44d32d4cd477a5595debb69bc7154923ac530433.tar.xz
syslinux-elf-44d32d4cd477a5595debb69bc7154923ac530433.zip
Further clean up the ext*fs installer
Diffstat (limited to 'extlinux')
-rw-r--r--extlinux/Makefile4
-rw-r--r--extlinux/extlinux.c142
2 files changed, 111 insertions, 35 deletions
diff --git a/extlinux/Makefile b/extlinux/Makefile
index 3358f5af..c3fd5dda 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -1,8 +1,8 @@
CC = gcc
-OPTFLAGS = -g -Os
+OPTFLAGS = -g -Os -DDEBUG
INCLUDES = -I. -I.. -I../libfat
CFLAGS = -W -Wall -Wno-sign-compare -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES)
-LDFLAGS = -s
+LDFLAGS = -g
SRCS = extlinux.c ../extlinux_bss_bin.c ../extlinux_sys_bin.c
OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS)))
diff --git a/extlinux/extlinux.c b/extlinux/extlinux.c
index 56641556..de85fc9a 100644
--- a/extlinux/extlinux.c
+++ b/extlinux/extlinux.c
@@ -36,6 +36,12 @@
#include <linux/hdreg.h> /* Hard disk geometry */
#include <linux/fs.h> /* FIGETBSZ, FIBMAP */
+#ifdef DEBUG
+# define dprintf printf
+#else
+# define dprintf(...) ((void)0)
+#endif
+
#define LDLINUX_MAGIC 0x3eb202fe
enum bs_offsets {
@@ -249,7 +255,7 @@ sectmap(int fd, uint32_t *sectors, int nsectors)
while ( nsectors ) {
blk = nblk++;
- printf("querying block %u\n", blk);
+ dprintf("querying block %u\n", blk);
if ( ioctl(fd, FIBMAP, &blk) )
return -1;
@@ -258,7 +264,7 @@ sectmap(int fd, uint32_t *sectors, int nsectors)
if ( !nsectors )
return 0;
- printf("Sector: %10u\n", blk);
+ dprintf("Sector: %10u\n", blk);
*sectors++ = blk++;
nsectors--;
}
@@ -268,57 +274,128 @@ sectmap(int fd, uint32_t *sectors, int nsectors)
}
/*
+ * Get the size of a block device
+ */
+uint64_t get_size(int devfd)
+{
+ uint64_t bytes;
+ uint32_t sects;
+ struct stat st;
+
+ if ( !ioctl(devfd, BLKGETSIZE64, &bytes) )
+ return bytes;
+ else if ( !ioctl(devfd, BLKGETSIZE, &sects) )
+ return (uint64_t)sects << 9;
+ else if ( !fstat(devfd, &st) && st.st_size )
+ return st.st_size;
+ else
+ return 0;
+}
+
+
+/*
+ * Get device geometry and partition offset
+ */
+struct geometry_table {
+ off_t bytes;
+ struct hd_big_geometry g;
+};
+
+/* Anyone have the zipdisk and LS120/LS240 geometries? */
+static const struct geometry_table standard_geometries[] = {
+ { 360*1024, { 2, 9, 40, 0 } },
+ { 720*1024, { 2, 9, 80, 0 } },
+ { 1200*1024, { 2, 15, 80, 0 } },
+ { 1440*1024, { 2, 18, 80, 0 } },
+ { 1680*1024, { 2, 21, 80, 0 } },
+ { 1722*1024, { 2, 21, 80, 0 } },
+ { 3840*1024, { 2, 36, 80, 0 } },
+ { 0, {0,0,0,0} }
+};
+
+int
+get_geometry(int devfd, uint64_t totalbytes, struct hd_big_geometry *geo)
+{
+ struct hd_geometry hd_geo;
+ struct floppy_struct fd_str;
+ const struct geometry_table *gp;
+
+ memset(geo, 0, sizeof *geo);
+
+ if ( !ioctl(devfd, HDIO_GETGEO_BIG, &geo) ) {
+ return 0;
+ } else if ( !ioctl(devfd, HDIO_GETGEO, &hd_geo) ) {
+ geo->heads = hd_geo.heads;
+ geo->sectors = hd_geo.sectors;
+ geo->cylinders = hd_geo.cylinders;
+ geo->start = hd_geo.start;
+ return 0;
+ } else if ( !ioctl(devfd, FDGETPRM, &fd_str) ) {
+ geo->heads = fd_str.head;
+ geo->sectors = fd_str.sect;
+ geo->cylinders = fd_str.track;
+ geo->start = 0;
+ }
+
+ /* Didn't work. Let's see if this is one of the standard geometries */
+ for ( gp = standard_geometries ; gp->bytes ; gp++ ) {
+ if ( gp->bytes == totalbytes ) {
+ memcpy(geo, &gp->g, sizeof *geo);
+ return 0;
+ }
+ }
+
+ /* Nope, didn't work; hope this is a hard disk-type device or EDD capable */
+ fprintf(stderr, "Warning: unable to obtain device geometry (may or may not work)\n");
+ return 1;
+}
+
+/*
* 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.
*/
void
-patch_file_and_bootblock(int fd, int dirfd)
+patch_file_and_bootblock(int fd, int dirfd, int devfd)
{
struct stat dirst;
- struct hd_geometry hd_geo;
- struct floppy_struct fd_str;
- uint16_t heads, cylinders;
- uint32_t sectors, offset;
+ struct hd_big_geometry geo;
uint32_t *sectp;
+ uint64_t totalbytes, totalsectors;
int nsect;
unsigned char *p, *patcharea;
int i, dw;
uint32_t csum;
- if ( ioctl(fd, HDIO_GETGEO, &hd_geo) == 0 ) {
- heads = hd_geo.heads;
- sectors = hd_geo.sectors;
- cylinders = hd_geo.cylinders;
- offset = hd_geo.start;
- } else if ( ioctl(fd, FDGETPRM, &fd_str) == 0 ) {
- heads = fd_str.head;
- sectors = fd_str.sect;
- cylinders = fd_str.track;
- offset = 0;
- } else {
- fprintf(stderr, "Warning: unable to obtain device geometry (may or may not work)\n");
- heads = sectors = cylinders = offset = 0;
- }
-
if ( fstat(dirfd, &dirst) ) {
perror("fstat dirfd");
exit(255); /* This should never happen */
}
+ totalbytes = get_size(devfd);
+ get_geometry(devfd, totalbytes, &geo);
+
/* Patch this into a fake FAT superblock. This isn't because
FAT is a good format in any way, it's because it lets the
early bootstrap share code with the FAT version. */
- printf("cyl = %u, heads = %u, sect = %u\n", cylinders, heads, sectors);
+ dprintf("cyl = %u, heads = %u, sect = %u\n", geo.cylinders, geo.heads, geo.sectors);
+
+ totalsectors = totalbytes >> SECTOR_SHIFT;
+ if ( totalsectors >= 65536 ) {
+ set_16(boot_block+bsSectors, 0);
+ } else {
+ set_16(boot_block+bsSectors, totalsectors);
+ }
+ set_32(boot_block+bsHugeSectors, totalsectors);
- set_16(boot_block+bsBytesPerSec, 512);
- set_16(boot_block+bsSecPerTrack, sectors);
- set_16(boot_block+bsHeads, heads);
- set_32(boot_block+bsHiddenSecs, offset);
+ set_16(boot_block+bsBytesPerSec, SECTOR_SIZE);
+ set_16(boot_block+bsSecPerTrack, geo.sectors);
+ set_16(boot_block+bsHeads, geo.heads);
+ set_32(boot_block+bsHiddenSecs, geo.start);
/* Construct the boot file */
- printf("directory inode = %lu\n", (unsigned long) dirst.st_ino);
+ dprintf("directory inode = %lu\n", (unsigned long) dirst.st_ino);
nsect = (boot_image_len+SECTOR_SIZE-1) >> SECTOR_SHIFT;
sectp = alloca(sizeof(uint32_t)*nsect);
if ( sectmap(fd, sectp, nsect) ) {
@@ -364,7 +441,7 @@ patch_file_and_bootblock(int fd, int dirfd)
* Must be run AFTER install_file()!
*/
int
-install_bootblock(int fd, char *device)
+install_bootblock(int fd, const char *device)
{
struct ext2_super_block sb;
@@ -387,7 +464,7 @@ install_bootblock(int fd, char *device)
}
int
-install_file(char *path, struct stat *rst)
+install_file(char *path, int devfd, struct stat *rst)
{
char *file;
int fd = -1, dirfd = -1, flags;
@@ -438,8 +515,7 @@ install_file(char *path, struct stat *rst)
}
/* Map the file, and patch the initial sector accordingly */
- patch_file_and_bootblock(fd, dirfd);
- patch_file_and_bootblock(fd, dirfd);
+ patch_file_and_bootblock(fd, dirfd, devfd);
/* Write it again - this relies on the file being overwritten in place! */
if ( xpwrite(fd, boot_image, boot_image_len, 0) != boot_image_len ) {
@@ -513,7 +589,7 @@ install_loader(char *path)
return 1;
}
- install_file(path, &fst);
+ install_file(path, devfd, &fst);
if ( fst.st_dev != st.st_dev ) {
fprintf(stderr, "%s: file system changed under us - aborting!\n",