summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-05-14 16:33:37 -0700
committerH. Peter Anvin <hpa@zytor.com>2009-05-14 16:33:37 -0700
commit0046660e3849bef9d922ba69d07c5bc639d1d133 (patch)
tree0d60efb691e622912682b7bab367a51ce8ead76e
parent1c7146a2eeaaf0021cc15e682e12609a652ed870 (diff)
downloadsyslinux-0046660e3849bef9d922ba69d07c5bc639d1d133.tar.gz
core: handle more than 32K of code for disk-based derivatives
Handle more than 32K worth of code for disk-based derivatives. We do this by allowing the sector pointers to overflow past sector 1; this is OK because we limit a run to be based on only the pointers that we have read so far. XXX: This is implemented for EXTLINUX, but breaks SYSLINUX. Need to update (and unify!) the SYSLINUX installers to cope. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/adv.inc14
-rw-r--r--core/diskstart.inc56
-rw-r--r--core/init.inc2
-rw-r--r--core/ldlinux.asm1
-rw-r--r--extlinux/main.c125
-rw-r--r--libinstaller/setadv.c13
-rw-r--r--libinstaller/syslxint.h78
7 files changed, 172 insertions, 117 deletions
diff --git a/core/adv.inc b/core/adv.inc
index c1a2628e..cfb39bdc 100644
--- a/core/adv.inc
+++ b/core/adv.inc
@@ -67,24 +67,26 @@ adv_init:
cmp byte [ADVDrive],-1
jne adv_read
-;%if IS_SYSLINUX || IS_MDSLINUX || IS_EXTLINUX
-%if IS_EXTLINUX ; Not yet implemented for the other derivatives
+%if IS_SYSLINUX || IS_EXTLINUX
+ cmp word [ADVSectors],2 ; Not present?
+ jb adv_verify
+
;
; Update pointers to default ADVs...
;
- mov bx,[LDLSectors]
+ mov bx,[DataSectors]
shl bx,2
mov ecx,[bsHidden]
- mov eax,[bx+SectorPtrs-8]
- mov edx,[bx+SectorPtrs-4]
+ mov eax,[bx+SectorPtrs] ; First ADV sector
+ mov edx,[bx+SectorPtrs+4] ; Second ADV sector
add eax,ecx
add edx,ecx
mov [ADVSec0],eax
mov [ADVSec1],edx
mov al,[DriveNumber]
mov [ADVDrive],al
+ jmp adv_read
%endif
- ; ** fall through to adv_verify **
;
; Initialize the ADV data structure in memory
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 0749dd84..c4fefbf1 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -482,18 +482,14 @@ ldlinux_magic dd LDLINUX_MAGIC
; LDLINUX_MAGIC, plus 8 bytes.
;
patch_area:
-LDLDwords dw 0 ; Total dwords starting at ldlinux_sys,
- ; not including ADVs
-LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
- ; but including any ADVs
+DataSectors dw 0 ; Number of sectors (not including bootsec)
+ADVSectors dw 0 ; Additional sectors for ADVs
+LDLDwords dd 0 ; Total dwords starting at ldlinux_sys,
CheckSum dd 0 ; Checksum starting at ldlinux_sys
; value = LDLINUX_MAGIC - [sum of dwords]
-%if IS_EXTLINUX
-CurrentDir dd 2 ; "Current" directory inode number
-%endif
-
-; Space for up to 64 sectors, the theoretical maximum
-SectorPtrs times 64 dd 0
+CurrentDir dd 2 ; "Current" directory inode number (EXTLINUX)
+SecPtrOffset dw SectorPtrs - ldlinux_sys
+SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2
ldlinux_ent:
;
@@ -534,13 +530,14 @@ BIOSName resw 1
; sector again, though.
;
load_rest:
- mov si,SectorPtrs
- mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
- mov cx,[LDLSectors]
+ lea esi,[SectorPtrs]
+ mov ebx,7C00h+2*SECTOR_SIZE ; Where we start loading
+ mov cx,[DataSectors]
+ dec cx ; Minus this sector
.get_chunk:
jcxz .done
- xor bp,bp
+ xor ebp,ebp
lodsd ; First sector of this chunk
mov edx,eax
@@ -549,6 +546,8 @@ load_rest:
inc bp
dec cx
jz .chunk_ready
+ cmp ebx,esi ; Pointer we don't have yet?
+ jae .chunk_ready
inc edx ; Next linear sector
cmp [si],edx ; Does it match
jnz .chunk_ready ; If not, this is it
@@ -556,9 +555,17 @@ load_rest:
jmp short .make_chunk
.chunk_ready:
+ push ebx
+ push es
+ shr ebx,4 ; Convert to a segment
+ mov es,bx
+ xor bx,bx
+ xor edx,edx ; Zero-extend LBA
call getlinsecsr
- shl bp,SECTOR_SHIFT
- add bx,bp
+ pop es
+ pop ebx
+ shl ebp,SECTOR_SHIFT
+ add ebx,ebp
jmp .get_chunk
.done:
@@ -572,10 +579,18 @@ verify_checksum:
mov si,ldlinux_sys
mov cx,[LDLDwords]
mov edx,-LDLINUX_MAGIC
+ push ds
.checksum:
lodsd
add edx,eax
+ and di,di
+ jnz .nowrap
+ mov ax,ds
+ add ax,1000h
+ mov ds,ax
+.nowrap:
loop .checksum
+ pop ds
and edx,edx ; Should be zero
jz all_read ; We're cool, go for it!
@@ -643,11 +658,18 @@ rl_checkpt equ $ ; Must be <= 8000h
rl_checkpt_off equ ($-$$)
%ifndef DEPEND
-%if rl_checkpt_off > 400h
+%if rl_checkpt_off > 3FCh ; Need one pointer in here
%error "Sector 1 overflow"
%endif
%endif
+; Sector pointers
+ alignz 4
+ global MaxInitDataSize
+MaxInitDataSize equ 96 << 10
+SectorPtrs times MaxInitDataSize >> SECTOR_SHIFT dd 0
+SectorPtrsEnd equ $
+
; ----------------------------------------------------------------------------
; End of code and data that have to be in the first sector
; ----------------------------------------------------------------------------
diff --git a/core/init.inc b/core/init.inc
index edfde5de..90c607ee 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -28,7 +28,7 @@ common_init:
mov edi,__pm_code_start
mov ecx,__pm_code_len
call bcopy
- or esi,-1 ; Set to zero
+ or esi,-1 ; bzero
mov edi,__bss_start
mov ecx,__bss_len
call bcopy
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index 6c5cac15..c9f3f955 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -963,7 +963,6 @@ readdir:
section .bss16
alignb 4
-CurrentDir resd 1 ; Current directory
PrevDir resd 1 ; Last scanned directory
section .text16
diff --git a/extlinux/main.c b/extlinux/main.c
index e9226fce..c4ccd538 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -63,12 +64,14 @@ struct my_options {
unsigned int sectors;
unsigned int heads;
int raid_mode;
+ int stupid_mode;
int reset_adv;
const char *set_once;
} opt = {
.sectors = 0,
.heads = 0,
.raid_mode = 0,
+ .stupid_mode = 0,
.reset_adv = 0,
.set_once = NULL,
};
@@ -82,6 +85,7 @@ static void __attribute__((noreturn)) usage(int rv)
" --zip -z Force zipdrive geometry (-H 64 -S 32)\n"
" --sectors=# -S Force the number of sectors per track\n"
" --heads=# -H Force number of heads\n"
+ " --stupid -s Slow, safe and stupid mode\n"
" --raid -r Fall back to the next device on boot failure\n"
" --once=... -o Execute a command once upon boot\n"
" --clear-once -O Clear the boot-once command\n"
@@ -109,6 +113,7 @@ static const struct option long_options[] = {
{ "update", 0, NULL, 'U' },
{ "zipdrive", 0, NULL, 'z' },
{ "sectors", 1, NULL, 'S' },
+ { "stupid", 0, NULL, 's' },
{ "heads", 1, NULL, 'H' },
{ "raid-mode", 0, NULL, 'r' },
{ "version", 0, NULL, 'v' },
@@ -126,57 +131,6 @@ static const char short_options[] = "iUuzS:H:rvho:O";
# define BLKGETSIZE64 _IOR(0x12,114,size_t)
#endif
-#define LDLINUX_MAGIC 0x3eb202fe
-
-enum bs_offsets {
- bsJump = 0x00,
- bsOemName = 0x03,
- bsBytesPerSec = 0x0b,
- bsSecPerClust = 0x0d,
- bsResSectors = 0x0e,
- bsFATs = 0x10,
- bsRootDirEnts = 0x11,
- bsSectors = 0x13,
- bsMedia = 0x15,
- bsFATsecs = 0x16,
- bsSecPerTrack = 0x18,
- bsHeads = 0x1a,
- bsHiddenSecs = 0x1c,
- bsHugeSectors = 0x20,
-
- /* FAT12/16 only */
- bs16DriveNumber = 0x24,
- bs16Reserved1 = 0x25,
- bs16BootSignature = 0x26,
- bs16VolumeID = 0x27,
- bs16VolumeLabel = 0x2b,
- bs16FileSysType = 0x36,
- bs16Code = 0x3e,
-
- /* FAT32 only */
- bs32FATSz32 = 36,
- bs32ExtFlags = 40,
- bs32FSVer = 42,
- bs32RootClus = 44,
- bs32FSInfo = 48,
- bs32BkBootSec = 50,
- bs32Reserved = 52,
- bs32DriveNumber = 64,
- bs32Reserved1 = 65,
- bs32BootSignature = 66,
- bs32VolumeID = 67,
- bs32VolumeLabel = 71,
- bs32FileSysType = 82,
- bs32Code = 90,
-
- bsSignature = 0x1fe
-};
-
-#define bsHead bsJump
-#define bsHeadLen (bsOemName-bsHead)
-#define bsCode bs32Code /* The common safe choice */
-#define bsCodeLen (bsSignature-bs32Code)
-
#ifndef EXT2_SUPER_OFFSET
#define EXT2_SUPER_OFFSET 1024
#endif
@@ -406,8 +360,10 @@ patch_file_and_bootblock(int fd, int dirfd, int devfd)
uint32_t *sectp;
uint64_t totalbytes, totalsectors;
int nsect;
- unsigned char *p, *patcharea;
- int i, dw;
+ uint32_t *wp;
+ struct boot_sector *bs;
+ struct patch_area *patcharea;
+ int i, dw, nptrs;
uint32_t csum;
if ( fstat(dirfd, &dirst) ) {
@@ -428,26 +384,28 @@ patch_file_and_bootblock(int fd, int dirfd, 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;
+
totalsectors = totalbytes >> SECTOR_SHIFT;
if ( totalsectors >= 65536 ) {
- set_16(boot_block+bsSectors, 0);
+ set_16(&bs->bsSectors, 0);
} else {
- set_16(boot_block+bsSectors, totalsectors);
+ set_16(&bs->bsSectors, totalsectors);
}
- set_32(boot_block+bsHugeSectors, totalsectors);
+ set_32(&bs->bsHugeSectors, totalsectors);
- 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);
+ 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(boot_block+0x1FE);
+ i = get_16(&bs->bsSignature);
if (opt.raid_mode)
- set_16(boot_block+i, 0x18CD); /* INT 18h */
+ set_16((uint16_t *)(boot_block+i), 0x18CD); /* INT 18h */
- set_16(boot_block+0x1FE, 0xAA55);
+ set_16(&bs->bsSignature, 0xAA55);
/* Construct the boot file */
@@ -461,37 +419,39 @@ patch_file_and_bootblock(int fd, int dirfd, int devfd)
}
/* First sector need pointer in boot sector */
- set_32(boot_block+0x1F8, *sectp++);
- nsect--;
+ set_32(&bs->NextSector, *sectp++);
+
+ /* Stupid mode? */
+ if (opt.stupid_mode)
+ set_16(&bs->MaxTransfer, 1);
/* Search for LDLINUX_MAGIC to find the patch area */
- for ( p = boot_image ; get_32(p) != LDLINUX_MAGIC ; p += 4 );
- patcharea = p+8;
+ for (wp = (uint32_t *)boot_image; get_32(wp) != LDLINUX_MAGIC; wp++);
+ patcharea = (struct patch_area *)wp;
/* Set up the totals */
dw = boot_image_len >> 2; /* COMPLETE dwords, excluding ADV */
- set_16(patcharea, dw);
- set_16(patcharea+2, nsect); /* Not including the first sector, but
- including the ADV */
- set_32(patcharea+8, dirst.st_ino); /* "Current" directory */
+ set_16(&patcharea->data_sectors, nsect-2); /* -2 for the ADVs */
+ set_16(&patcharea->adv_sectors, 2);
+ set_32(&patcharea->dwords, dw);
+ set_32(&patcharea->currentdir, dirst.st_ino);
/* Set the sector pointers */
- p = patcharea+12;
+ wp = (uint32_t *)((char *)boot_image+get_16(&patcharea->secptroffset));
+ nptrs = get_16(&patcharea->secptrcnt);
- memset(p, 0, 64*4);
- while ( nsect-- ) {
- set_32(p, *sectp++);
- p += 4;
- }
+ memset(wp, 0, nptrs*4);
+ while ( nsect-- )
+ set_32(wp++, *sectp++);
/* Now produce a checksum */
- set_32(patcharea+4, 0);
+ set_32(&patcharea->checksum, 0);
csum = LDLINUX_MAGIC;
- for ( i = 0, p = boot_image ; i < dw ; i++, p += 4 )
- csum -= get_32(p); /* Negative checksum */
+ for (i = 0, wp = (uint32_t *)boot_image; i < dw; i++, wp++)
+ csum -= get_32(wp); /* Negative checksum */
- set_32(patcharea+4, csum);
+ set_32(&patcharea->checksum, csum);
}
/*
@@ -981,6 +941,9 @@ main(int argc, char *argv[])
case 'r':
opt.raid_mode = 1;
break;
+ case 's':
+ opt.stupid_mode = 1;
+ break;
case 'i':
update_only = 0;
break;
diff --git a/libinstaller/setadv.c b/libinstaller/setadv.c
index c768d1b1..c57f0974 100644
--- a/libinstaller/setadv.c
+++ b/libinstaller/setadv.c
@@ -36,14 +36,14 @@ static void cleanup_adv(unsigned char *advbuf)
uint32_t csum;
/* Make sure both copies agree, and update the checksum */
- set_32(advbuf, ADV_MAGIC1);
+ set_32((uint32_t *)advbuf, ADV_MAGIC1);
csum = ADV_MAGIC2;
for (i = 8; i < ADV_SIZE-4; i += 4)
- csum -= get_32(advbuf+i);
+ csum -= get_32((uint32_t *)(advbuf+i));
- set_32(advbuf+4, csum);
- set_32(advbuf+ADV_SIZE-4, ADV_MAGIC3);
+ set_32((uint32_t *)(advbuf+4), csum);
+ set_32((uint32_t *)(advbuf+ADV_SIZE-4), ADV_MAGIC3);
memcpy(advbuf+ADV_SIZE, advbuf, ADV_SIZE);
}
@@ -130,12 +130,13 @@ static int adv_consistent(const unsigned char *p)
int i;
uint32_t csum;
- if (get_32(p) != ADV_MAGIC1 || get_32(p+ADV_SIZE-4) != ADV_MAGIC3)
+ if (get_32((uint32_t *)p) != ADV_MAGIC1 ||
+ get_32((uint32_t *)(p+ADV_SIZE-4)) != ADV_MAGIC3)
return 0;
csum = 0;
for (i = 4; i < ADV_SIZE-4; i += 4)
- csum += get_32(p+i);
+ csum += get_32((uint32_t *)(p+i));
return csum == ADV_MAGIC2;
}
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index 120026de..3cecf3c0 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -18,12 +18,12 @@
/*
* Access functions for littleendian numbers, possibly misaligned.
*/
-static inline uint8_t get_8(const unsigned char *p)
+static inline uint8_t get_8(const uint8_t *p)
{
return *(const uint8_t *)p;
}
-static inline uint16_t get_16(const unsigned char *p)
+static inline uint16_t get_16(const uint16_t *p)
{
#if defined(__i386__) || defined(__x86_64__)
/* Littleendian and unaligned-capable */
@@ -33,7 +33,7 @@ static inline uint16_t get_16(const unsigned char *p)
#endif
}
-static inline uint32_t get_32(const unsigned char *p)
+static inline uint32_t get_32(const uint32_t *p)
{
#if defined(__i386__) || defined(__x86_64__)
/* Littleendian and unaligned-capable */
@@ -44,7 +44,7 @@ static inline uint32_t get_32(const unsigned char *p)
#endif
}
-static inline void set_16(unsigned char *p, uint16_t v)
+static inline void set_16(uint16_t *p, uint16_t v)
{
#if defined(__i386__) || defined(__x86_64__)
/* Littleendian and unaligned-capable */
@@ -55,7 +55,7 @@ static inline void set_16(unsigned char *p, uint16_t v)
#endif
}
-static inline void set_32(unsigned char *p, uint32_t v)
+static inline void set_32(uint32_t *p, uint32_t v)
{
#if defined(__i386__) || defined(__x86_64__)
/* Littleendian and unaligned-capable */
@@ -71,4 +71,72 @@ static inline void set_32(unsigned char *p, uint32_t v)
#define SECTOR_SHIFT 9 /* 512-byte sectors */
#define SECTOR_SIZE (1 << SECTOR_SHIFT)
+#define LDLINUX_MAGIC 0x3eb202fe
+
+/* Patch area for disk-based installers */
+struct patch_area {
+ uint32_t magic; /* LDLINUX_MAGIC */
+ uint32_t instance; /* Per-version value */
+ uint16_t data_sectors;
+ uint16_t adv_sectors;
+ uint32_t dwords;
+ uint32_t checksum;
+ uint32_t currentdir;
+ uint16_t secptroffset;
+ uint16_t secptrcnt;
+};
+
+ /* FAT bootsector format, also used by other disk-based derivatives */
+struct boot_sector {
+ uint8_t bsJump[3];
+ char bsOemName[8];
+ uint16_t bsBytesPerSec;
+ uint8_t bsSecPerClust;
+ uint16_t bsResSectors;
+ uint8_t bsFATs;
+ uint16_t bsRootDirEnts;
+ uint16_t bsSectors;
+ uint8_t bsMedia;
+ uint16_t bsFATsecs;
+ uint16_t bsSecPerTrack;
+ uint16_t bsHeads;
+ uint32_t bsHiddenSecs;
+ uint32_t bsHugeSectors;
+
+ union {
+ struct {
+ uint8_t DriveNumber;
+ uint8_t Reserved1;
+ uint8_t BootSignature;
+ uint32_t VolumeID;
+ char VolumeLabel[11];
+ char FileSysType[8];
+ uint8_t Code[442];
+ } __attribute__((packed)) bs16;
+ struct {
+ uint32_t FATSz32;
+ uint16_t ExtFlags;
+ uint16_t FSVer;
+ uint32_t RootClus;
+ uint16_t FSInfo;
+ uint16_t BkBootSec;
+ uint8_t DriveNumber;
+ uint8_t Reserved1;
+ uint8_t BootSignature;
+ uint32_t VolumeID;
+ char VolumeLabel[11];
+ char FileSysType[8];
+ uint8_t Code[414];
+ } __attribute__((packed)) bs32;
+ } __attribute__((packed));
+
+ uint32_t NextSector; /* Pointer to the first unused sector */
+ uint16_t MaxTransfer; /* Max sectors per transfer */
+ uint16_t bsSignature;
+} __attribute__((packed));
+
+#define bsHead bsJump
+#define bsHeadLen offsetof(struct boot_sector, bsJump)
+#define bsCode bs32.Code /* The common safe choice */
+
#endif /* SYSLXINT_H */