aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS8
-rw-r--r--bootsect.inc3
-rw-r--r--com32.inc3
-rw-r--r--com32/include/stdio.h7
-rw-r--r--com32/include/syslinux/loadfile.h3
-rw-r--r--com32/include/syslinux/zio.h13
-rw-r--r--com32/lib/Makefile11
-rw-r--r--com32/lib/fclose.c11
-rw-r--r--com32/lib/memcpy.S1
-rw-r--r--com32/lib/mempcpy.S1
-rw-r--r--com32/lib/memset.c16
-rw-r--r--com32/lib/realloc.c3
-rw-r--r--com32/lib/sys/file.h11
-rw-r--r--com32/lib/sys/fileread.c44
-rw-r--r--com32/lib/sys/fstat.c11
-rw-r--r--com32/lib/sys/vesa/background.c149
-rw-r--r--com32/lib/sys/vesa/drawtxt.c2
-rw-r--r--com32/lib/sys/vesa/fill.h6
-rw-r--r--com32/lib/sys/zfile.c171
-rw-r--r--com32/lib/sys/zfopen.c44
-rw-r--r--com32/lib/syslinux/floadfile.c108
-rw-r--r--com32/lib/syslinux/loadfile.c65
-rw-r--r--com32/lib/syslinux/zloadfile.c59
-rw-r--r--com32/modules/elf.c2
-rw-r--r--com32/modules/mboot.c6
-rw-r--r--comboot.inc17
-rw-r--r--doc/comboot.txt10
-rw-r--r--extlinux.asm34
-rw-r--r--font.inc10
-rw-r--r--getc.inc32
-rw-r--r--isolinux.asm39
-rw-r--r--kernel.inc7
-rw-r--r--ldlinux.asm40
-rw-r--r--loadhigh.inc46
-rwxr-xr-xppmtolss164
-rw-r--r--pxelinux.asm180
-rw-r--r--runkernel.inc437
-rw-r--r--ui.inc13
-rw-r--r--version2
39 files changed, 1118 insertions, 511 deletions
diff --git a/NEWS b/NEWS
index d21fe777..7b444fe2 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,14 @@ Starting with 1.47, changes marked with SYSLINUX/PXELINUX/ISOLINUX
apply to that specific program only; other changes apply to all of
them.
+Changes in 3.70:
+ * Substantial infrastructure changes to support files whose
+ length aren't known at open time (typically network
+ connections.) Please note that the semantics of some of the
+ comboot APIs have changed slightly; please see doc/comboot.doc.
+ * PXELINUX: We no longer require a TFTP server which supports
+ the tsize option for all transfers.
+
Changes in 3.62:
* Clean up garbage after "aborted." message.
* Clean up memdump.com filenames.
diff --git a/bootsect.inc b/bootsect.inc
index 71d595a9..7e8f416d 100644
--- a/bootsect.inc
+++ b/bootsect.inc
@@ -34,9 +34,6 @@ is_bss_sector:
mov byte [CopySuper],superblock_len
%endif
load_bootsec:
- xchg dx,ax
- shl eax,16
- xchg dx,ax ; Now EAX = file length
mov edi, 100000h
mov [trackbuf+4],edi ; Copy from this address
push edi ; Save load address
diff --git a/com32.inc b/com32.inc
index ac513593..99954206 100644
--- a/com32.inc
+++ b/com32.inc
@@ -43,8 +43,7 @@ com32_rmidt:
section .text
is_com32_image:
push si ; Save file handle
- push dx ; File length held in DX:AX
- push ax
+ push eax ; Save file length
call make_plain_cmdline
; Copy the command line into the low cmdline buffer
diff --git a/com32/include/stdio.h b/com32/include/stdio.h
index 7cbb4b89..bbb75529 100644
--- a/com32/include/stdio.h
+++ b/com32/include/stdio.h
@@ -54,12 +54,7 @@ static __inline__ FILE *fdopen(int __fd, const char *__m)
{
(void)__m; return __create_file(__fd);
}
-static __inline__ int fclose(FILE *__f)
-{
- extern int close(int);
- return close(fileno(__f));
-}
-
+__extern int fclose(FILE *__f);
__extern int fputs(const char *, FILE *);
__extern int puts(const char *);
__extern int fputc(int, FILE *);
diff --git a/com32/include/syslinux/loadfile.h b/com32/include/syslinux/loadfile.h
index fbda589d..1a04c51f 100644
--- a/com32/include/syslinux/loadfile.h
+++ b/com32/include/syslinux/loadfile.h
@@ -2,11 +2,14 @@
#define LIBUTIL_LOADFILE_H
#include <stddef.h>
+#include <stdio.h>
/* loadfile() returns the true size of the file, but will guarantee valid,
zero-padded memory out to this boundary. */
#define LOADFILE_ZERO_PAD 64
int loadfile(const char *, void **, size_t *);
+int zloadfile(const char *, void **, size_t *);
+int floadfile(FILE *, void **, size_t *, const void *, size_t);
#endif
diff --git a/com32/include/syslinux/zio.h b/com32/include/syslinux/zio.h
new file mode 100644
index 00000000..23991e50
--- /dev/null
+++ b/com32/include/syslinux/zio.h
@@ -0,0 +1,13 @@
+/*
+ * <syslinux/zio.h>
+ */
+
+#ifndef _SYSLINUX_ZIO_H
+#define _SYSLINUX_ZIO_H
+
+#include <stdio.h>
+
+int zopen(const char *, int, ...);
+FILE *zfopen(const char *, const char *);
+
+#endif /* _SYSLINUX_ZIO_H */
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 810c2bc5..6c08c221 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -4,7 +4,7 @@ include MCONFIG
LIBOBJS = \
abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \
ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \
- putchar.o setjmp.o \
+ fclose.o putchar.o setjmp.o \
fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o getopt.o \
lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \
memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \
@@ -29,7 +29,11 @@ LIBOBJS = \
sys/entry.o sys/exit.o sys/argv.o sys/times.o \
sys/fileinfo.o sys/opendev.o sys/read.o sys/write.o sys/ftell.o \
sys/close.o sys/open.o sys/fileread.o sys/fileclose.o \
- sys/isatty.o sys/fstat.o sys/openconsole.o sys/line_input.o \
+ sys/isatty.o sys/fstat.o \
+ \
+ sys/zfile.o sys/zfopen.o \
+ \
+ sys/openconsole.o sys/line_input.o \
sys/colortable.o sys/screensize.o \
\
sys/stdcon_read.o sys/stdcon_write.o sys/rawcon_read.o \
@@ -78,7 +82,8 @@ LIBOBJS = \
syslinux/run_default.o syslinux/run_command.o \
syslinux/cleanup.o syslinux/localboot.o syslinux/runimage.o \
\
- syslinux/loadfile.o \
+ syslinux/loadfile.o syslinux/floadfile.o syslinux/zloadfile.o \
+ \
syslinux/load_linux.o syslinux/initramfs.o \
syslinux/initramfs_file.o syslinux/initramfs_loadfile.o \
syslinux/initramfs_archive.o \
diff --git a/com32/lib/fclose.c b/com32/lib/fclose.c
new file mode 100644
index 00000000..41f6a62c
--- /dev/null
+++ b/com32/lib/fclose.c
@@ -0,0 +1,11 @@
+/*
+ * fclose.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int fclose(FILE *__f)
+{
+ return close(fileno(__f));
+}
diff --git a/com32/lib/memcpy.S b/com32/lib/memcpy.S
index ed8e20e3..a893d247 100644
--- a/com32/lib/memcpy.S
+++ b/com32/lib/memcpy.S
@@ -19,7 +19,6 @@ memcpy:
movl %ecx, %edx
shrl $2, %ecx
- cld
rep ; movsl
jnc 1f # The shrl had carry out if odd word count
diff --git a/com32/lib/mempcpy.S b/com32/lib/mempcpy.S
index aa17f471..eeab9187 100644
--- a/com32/lib/mempcpy.S
+++ b/com32/lib/mempcpy.S
@@ -19,7 +19,6 @@ mempcpy:
movl %ecx, %edx
shrl $2, %ecx
- cld
rep ; movsl
jnc 1f # The shrl had carry out if odd word count
diff --git a/com32/lib/memset.c b/com32/lib/memset.c
index 522cc59a..516ad475 100644
--- a/com32/lib/memset.c
+++ b/com32/lib/memset.c
@@ -8,23 +8,11 @@
void *memset(void *dst, int c, size_t n)
{
char *q = dst;
-
-#if defined(__i386__)
size_t nl = n >> 2;
- asm volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+
+ asm volatile("rep ; stosl ; movl %3,%0 ; rep ; stosb"
: "+c" (nl), "+D" (q)
: "a" ((unsigned char)c * 0x01010101U), "r" (n & 3));
-#elif defined(__x86_64__)
- size_t nq = n >> 3;
- asm volatile("cld ; rep ; stosq ; movl %3,%%ecx ; rep ; stosb"
- : "+c" (nq), "+D" (q)
- : "a" ((unsigned char)c * 0x0101010101010101U),
- "r" ((uint32_t)n & 7));
-#else
- while ( n-- ) {
- *q++ = c;
- }
-#endif
return dst;
}
diff --git a/com32/lib/realloc.c b/com32/lib/realloc.c
index 89b63c8e..2161a758 100644
--- a/com32/lib/realloc.c
+++ b/com32/lib/realloc.c
@@ -31,7 +31,8 @@ void *realloc(void *ptr, size_t size)
/* Add the obligatory arena header, and round up */
newsize = (size+2*sizeof(struct arena_header)-1) & ARENA_SIZE_MASK;
- if ( oldsize >= newsize && newsize >= (oldsize >> 2) ) {
+ if ( oldsize >= newsize && newsize >= (oldsize >> 2) &&
+ oldsize-newsize < 4096 ) {
/* This allocation is close enough already. */
return ptr;
} else {
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index bca40f70..11dacd80 100644
--- a/com32/lib/sys/file.h
+++ b/com32/lib/sys/file.h
@@ -80,6 +80,11 @@ struct file_info {
const struct input_dev *iop; /* Input operations */
const struct output_dev *oop; /* Output operations */
+ /* Output file data */
+ struct {
+ int rows, cols; /* Rows and columns */
+ } o;
+
/* Structure used for input blocking */
struct {
int blocklg2; /* Blocksize log 2 */
@@ -89,13 +94,9 @@ struct file_info {
uint16_t _filler; /* Unused */
size_t nbytes; /* Number of bytes available in buffer */
char *datap; /* Current data pointer */
+ void *pvt; /* Private pointer for driver */
char buf[MAXBLOCK];
} i;
-
- /* Output file data */
- struct {
- int rows, cols; /* Rows and columns */
- } o;
};
extern struct file_info __file_info[NFILES];
diff --git a/com32/lib/sys/fileread.c b/com32/lib/sys/fileread.c
index fe20e64b..79d912d5 100644
--- a/com32/lib/sys/fileread.c
+++ b/com32/lib/sys/fileread.c
@@ -37,37 +37,45 @@
#include <minmax.h>
#include "file.h"
-ssize_t __file_read(struct file_info *fp, void *buf, size_t count)
+int __file_get_block(struct file_info *fp)
{
com32sys_t ireg, oreg;
- char *bufp = buf;
- size_t n = 0;
- size_t ncopy;
memset(&ireg, 0, sizeof ireg);
ireg.eax.w[0] = 0x0007; /* Read file */
ireg.ebx.w[0] = OFFS(__com32.cs_bounce);
ireg.es = SEG(__com32.cs_bounce);
+ ireg.esi.w[0] = fp->i.filedes;
+ ireg.ecx.w[0] = MAXBLOCK >> fp->i.blocklg2;
+
+ __intcall(0x22, &ireg, &oreg);
+
+ if ( oreg.eflags.l & EFLAGS_CF ) {
+ errno = EIO;
+ return -1;
+ }
+
+ fp->i.filedes = oreg.esi.w[0];
+ fp->i.nbytes = oreg.ecx.l;
+ fp->i.datap = fp->i.buf;
+ memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes);
+
+ return 0;
+}
+
+ssize_t __file_read(struct file_info *fp, void *buf, size_t count)
+{
+ char *bufp = buf;
+ ssize_t n = 0;
+ size_t ncopy;
while ( count ) {
if ( fp->i.nbytes == 0 ) {
if ( fp->i.offset >= fp->i.length || !fp->i.filedes )
return n; /* As good as it gets... */
- ireg.esi.w[0] = fp->i.filedes;
- ireg.ecx.w[0] = MAXBLOCK >> fp->i.blocklg2;
-
- __intcall(0x22, &ireg, &oreg);
-
- if ( oreg.eflags.l & EFLAGS_CF ) {
- errno = EIO;
- return -1;
- }
-
- fp->i.filedes = oreg.esi.w[0];
- fp->i.nbytes = min(fp->i.length-fp->i.offset, (unsigned)MAXBLOCK);
- fp->i.datap = fp->i.buf;
- memcpy(fp->i.buf, __com32.cs_bounce, fp->i.nbytes);
+ if ( __file_get_block(fp) )
+ return n ? n : -1;
}
ncopy = min(count, fp->i.nbytes);
diff --git a/com32/lib/sys/fstat.c b/com32/lib/sys/fstat.c
index 3a42ab85..ef5e20dc 100644
--- a/com32/lib/sys/fstat.c
+++ b/com32/lib/sys/fstat.c
@@ -45,8 +45,15 @@ int fstat(int fd, struct stat *buf)
}
if ( fp->iop->flags & __DEV_FILE ) {
- buf->st_mode = S_IFREG | 0444;
- buf->st_size = fp->i.length;
+ if ( fp->i.length == (uint32_t)-1 ) {
+ /* File of unknown length, report it as a socket
+ (it probably really is, anyway!) */
+ buf->st_mode = S_IFSOCK | 0444;
+ buf->st_size = 0;
+ } else {
+ buf->st_mode = S_IFREG | 0444;
+ buf->st_size = fp->i.length;
+ }
} else {
buf->st_mode = S_IFCHR | 0666;
buf->st_size = 0;
diff --git a/com32/lib/sys/vesa/background.c b/com32/lib/sys/vesa/background.c
index 3bdda208..f6b7b779 100644
--- a/com32/lib/sys/vesa/background.c
+++ b/com32/lib/sys/vesa/background.c
@@ -33,18 +33,11 @@
#include <stdlib.h>
#include <sys/stat.h>
#include <minmax.h>
+#include <stdbool.h>
+#include <syslinux/loadfile.h>
#include "vesa.h"
#include "video.h"
-static size_t filesize(FILE *fp)
-{
- struct stat st;
- if (fstat(fileno(fp), &st))
- return 0;
- else
- return st.st_size;
-}
-
/*** FIX: This really should be alpha-blended with color index 0 ***/
/* For best performance, "start" should be a multiple of 4, to assure
@@ -172,19 +165,16 @@ static int jpeg_sig_cmp(uint8_t *bytes, int len)
static int read_jpeg_file(FILE *fp, uint8_t *header, int len)
{
struct jdec_private *jdec = NULL;
- unsigned char *jpeg_file = NULL;
- size_t length_of_file = filesize(fp);
+ void *jpeg_file = NULL;
+ size_t length_of_file;
unsigned int width, height;
int rv = -1;
unsigned char *components[1];
unsigned int bytes_per_row[1];
- jpeg_file = malloc(length_of_file);
- if (!jpeg_file)
- goto err;
-
- memcpy(jpeg_file, header, len);
- if (fread(jpeg_file+len, 1, length_of_file-len, fp) != length_of_file-len)
+ rv = floadfile(fp, &jpeg_file, &length_of_file, header, len);
+ fclose(fp);
+ if (rv)
goto err;
jdec = tinyjpeg_init();
@@ -253,7 +243,7 @@ int vesacon_set_background(unsigned int rgb)
if (__vesacon_pixel_format == PXF_NONE)
return 0; /* Not in graphics mode */
- asm volatile("cld; rep; stosl"
+ asm volatile("rep; stosl"
: "+D" (bgptr), "+c" (count)
: "a" (rgb)
: "memory");
@@ -262,6 +252,127 @@ int vesacon_set_background(unsigned int rgb)
return 0;
}
+struct lss16_header {
+ uint32_t magic;
+ uint16_t xsize;
+ uint16_t ysize;
+};
+
+#define LSS16_MAGIC 0x1413f33d
+
+static inline int lss16_sig_cmp(const void *header, int len)
+{
+ const struct lss16_header *h = header;
+
+ if (len != 8)
+ return 1;
+
+ return !(h->magic == LSS16_MAGIC &&
+ h->xsize <= VIDEO_X_SIZE && h->ysize <= VIDEO_Y_SIZE);
+}
+
+static int read_lss16_file(FILE *fp, const void *header, int header_len)
+{
+ const struct lss16_header *h = header;
+ uint32_t colors[16], color;
+ bool has_nybble;
+ uint8_t byte;
+ int count;
+ int nybble, prev;
+ enum state {
+ st_start,
+ st_c0,
+ st_c1,
+ st_c2,
+ } state;
+ int i, x, y;
+ uint32_t *bgptr = (void *)__vesacon_background;
+
+ /* Assume the header, 8 bytes, has already been loaded. */
+ if (header_len != 8)
+ return -1;
+
+ for (i = 0; i < 16; i++) {
+ uint8_t rgb[3];
+ if (fread(rgb, 1, 3, fp) != 3)
+ return -1;
+
+ colors[i] = (((rgb[0] & 63)*255/63) << 16) +
+ (((rgb[1] & 63)*255/63) << 8) +
+ ((rgb[2] & 63)*255/63);
+ }
+
+ /* By spec, the state machine is per row */
+ for (y = 0; y < h->ysize; y++) {
+ state = st_start;
+ has_nybble = false;
+ color = colors[prev = 0]; /* By specification */
+ count = 0;
+
+ x = 0;
+ while (x < h->xsize) {
+ if (!has_nybble) {
+ if (fread(&byte, 1, 1, fp) != 1)
+ return -1;
+ nybble = byte & 0xf;
+ has_nybble = true;
+ } else {
+ nybble = byte >> 4;
+ has_nybble = false;
+ }
+
+ switch (state) {
+ case st_start:
+ if (nybble != prev) {
+ *bgptr++ = color = colors[prev = nybble];
+ x++;
+ } else {
+ state = st_c0;
+ }
+ break;
+
+ case st_c0:
+ if (nybble == 0) {
+ state = st_c1;
+ } else {
+ count = nybble;
+ goto do_run;
+ }
+ break;
+
+ case st_c1:
+ count = nybble + 16;
+ state = st_c2;
+ break;
+
+ case st_c2:
+ count += nybble << 4;
+ goto do_run;
+
+ do_run:
+ count = min(count, h->xsize-x);
+ x += count;
+ asm volatile("rep; stosl"
+ : "+D" (bgptr), "+c" (count) : "a" (color));
+ state = st_start;
+ break;
+ }
+ }
+
+ /* Zero-fill rest of row */
+ i = VIDEO_X_SIZE-x;
+ asm volatile("rep; stosl"
+ : "+D" (bgptr), "+c" (i) : "a" (0) : "memory");
+ }
+
+ /* Zero-fill rest of screen */
+ i = (VIDEO_Y_SIZE-y)*VIDEO_X_SIZE;
+ asm volatile("rep; stosl"
+ : "+D" (bgptr), "+c" (i) : "a" (0) : "memory");
+
+ return 0;
+}
+
int vesacon_load_background(const char *filename)
{
FILE *fp = NULL;
@@ -283,6 +394,8 @@ int vesacon_load_background(const char *filename)
rv = read_png_file(fp);
} else if (!jpeg_sig_cmp(header, 8)) {
rv = read_jpeg_file(fp, header, 8);
+ } else if (!lss16_sig_cmp(header, 8)) {
+ rv = read_lss16_file(fp, header, 8);
}
/* This actually displays the stuff */
diff --git a/com32/lib/sys/vesa/drawtxt.c b/com32/lib/sys/vesa/drawtxt.c
index 6e21a344..662eebef 100644
--- a/com32/lib/sys/vesa/drawtxt.c
+++ b/com32/lib/sys/vesa/drawtxt.c
@@ -40,7 +40,7 @@ static int cursor_x, cursor_y;
static inline void *copy_dword(void *dst, void *src, size_t dword_count)
{
- asm volatile("cld; rep; movsl"
+ asm volatile("rep; movsl"
: "+D" (dst), "+S" (src), "+c" (dword_count));
return dst; /* Updated destination pointer */
}
diff --git a/com32/lib/sys/vesa/fill.h b/com32/lib/sys/vesa/fill.h
index 4d4a9f97..63ca577b 100644
--- a/com32/lib/sys/vesa/fill.h
+++ b/com32/lib/sys/vesa/fill.h
@@ -37,19 +37,19 @@ static inline struct vesa_char *vesacon_fill(struct vesa_char *ptr,
{
switch (sizeof(struct vesa_char)) {
case 1:
- asm volatile("cld; rep; stosb"
+ asm volatile("rep; stosb"
: "+D" (ptr), "+c" (count)
: "a" (fill)
: "memory");
break;
case 2:
- asm volatile("cld; rep; stosw"
+ asm volatile("rep; stosw"
: "+D" (ptr), "+c" (count)
: "a" (fill)
: "memory");
break;
case 4:
- asm volatile("cld; rep; stosl"
+ asm volatile("rep; stosl"
: "+D" (ptr), "+c" (count)
: "a" (fill)
: "memory");
diff --git a/com32/lib/sys/zfile.c b/com32/lib/sys/zfile.c
new file mode 100644
index 00000000..9dbee9b9
--- /dev/null
+++ b/com32/lib/sys/zfile.c
@@ -0,0 +1,171 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2003-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <syslinux/zio.h>
+
+#include "file.h"
+#include "zlib.h"
+
+/*
+ * zopen.c
+ *
+ * Open an ordinary file, possibly compressed; if so, insert
+ * an appropriate decompressor.
+ */
+
+int __file_get_block(struct file_info *fp);
+int __file_close(struct file_info *fp);
+
+static ssize_t gzip_file_read(struct file_info *, void *, size_t);
+static int gzip_file_close(struct file_info *);
+
+static const struct input_dev gzip_file_dev = {
+ .dev_magic = __DEV_MAGIC,
+ .flags = __DEV_FILE | __DEV_INPUT,
+ .fileflags = O_RDONLY,
+ .read = gzip_file_read,
+ .close = gzip_file_close,
+ .open = NULL,
+};
+
+static int gzip_file_init(struct file_info *fp)
+{
+ z_streamp zs = calloc(1, sizeof(z_stream));
+
+ if (!zs)
+ return -1;
+
+ fp->i.pvt = zs;
+
+ zs->next_in = (void *)fp->i.datap;
+ zs->avail_in = fp->i.nbytes;
+
+ if (inflateInit2(zs, 15+32) != Z_OK) {
+ errno = EIO;
+ return -1;
+ }
+
+ fp->iop = &gzip_file_dev;
+ fp->i.length = -1; /* Unknown */
+
+ return 0;
+}
+
+static ssize_t gzip_file_read(struct file_info *fp, void *ptr, size_t n)
+{
+ z_streamp zs = fp->i.pvt;
+ int rv;
+ ssize_t bytes;
+ ssize_t nout = 0;
+ unsigned char *p = ptr;
+
+ while ( n ) {
+ zs->next_out = p;
+ zs->avail_out = n;
+
+ if (!zs->avail_in && fp->i.filedes) {
+ if (__file_get_block(fp))
+ return nout ? nout : -1;
+
+ zs->next_in = (void *)fp->i.datap;
+ zs->avail_in = fp->i.nbytes;
+ }
+
+ rv = inflate(zs, Z_SYNC_FLUSH);
+
+ bytes = n - zs->avail_out;
+ nout += bytes;
+ p += bytes;
+ n -= bytes;
+
+ switch (rv) {
+ case Z_DATA_ERROR:
+ case Z_NEED_DICT:
+ case Z_BUF_ERROR:
+ case Z_STREAM_ERROR:
+ default:
+ errno = EIO;
+ return nout ? nout : -1;
+ case Z_MEM_ERROR:
+ errno = ENOMEM;
+ return nout ? nout : -1;
+ case Z_STREAM_END:
+ return nout;
+ case Z_OK:
+ break;
+ }
+ }
+
+ return nout;
+}
+
+static int gzip_file_close(struct file_info *fp)
+{
+ z_streamp zs = fp->i.pvt;
+
+ inflateEnd(zs);
+ free(zs);
+ return __file_close(fp);
+}
+
+int zopen(const char *pathname, int flags, ...)
+{
+ int fd, rv;
+ struct file_info *fp;
+
+ /* We don't actually give a hoot about the creation bits... */
+ fd = open(pathname, flags, 0);
+
+ if ( fd < 0 )
+ return -1;
+
+ fp = &__file_info[fd];
+
+ /* Need to get the first block into the buffer, but not consumed */
+ if ( __file_get_block(fp) )
+ goto err;
+
+ if (fp->i.nbytes >= 14 &&
+ (uint8_t)fp->i.buf[0] == 037 &&
+ (uint8_t)fp->i.buf[1] == 0213 && /* gzip */
+ fp->i.buf[2] == 8) /* deflate */
+ rv = gzip_file_init(fp);
+ else
+ rv = 0; /* Plain file */
+
+ if (!rv)
+ return fd;
+
+ err:
+ close(fd);
+ return -1;
+}
diff --git a/com32/lib/sys/zfopen.c b/com32/lib/sys/zfopen.c
new file mode 100644
index 00000000..dfd45de3
--- /dev/null
+++ b/com32/lib/sys/zfopen.c
@@ -0,0 +1,44 @@
+/*
+ * zfopen.c
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <syslinux/zio.h>
+
+FILE *zfopen(const char *file, const char *mode)
+{
+ int flags = O_RDONLY;
+ int plus = 0;
+ int fd;
+
+ while ( *mode ) {
+ switch ( *mode ) {
+ case 'r':
+ flags = O_RDONLY;
+ break;
+ case 'w':
+ flags = O_WRONLY|O_CREAT|O_TRUNC;
+ break;
+ case 'a':
+ flags = O_WRONLY|O_CREAT|O_APPEND;
+ break;
+ case '+':
+ plus = 1;
+ break;
+ }
+ mode++;
+ }
+
+ if ( plus ) {
+ flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR;
+ }
+
+ fd = zopen(file, flags, 0666);
+
+ if ( fd < 0 )
+ return NULL;
+ else
+ return fdopen(fd, mode);
+}
diff --git a/com32/lib/syslinux/floadfile.c b/com32/lib/syslinux/floadfile.c
new file mode 100644
index 00000000..ea108294
--- /dev/null
+++ b/com32/lib/syslinux/floadfile.c
@@ -0,0 +1,108 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * floadfile.c
+ *
+ * Read the contents of a data file into a malloc'd buffer
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <syslinux/loadfile.h>
+
+#define INCREMENTAL_CHUNK 1024*1024
+
+int floadfile(FILE *f, void **ptr, size_t *len, const void *prefix,
+ size_t prefix_len)
+{
+ struct stat st;
+ void *data, *dp;
+ size_t alen, clen, rlen, xlen;
+
+ clen = alen = 0;
+ data = NULL;
+
+ if ( fstat(fileno(f), &st) )
+ goto err;
+
+ if (!S_ISREG(st.st_mode)) {
+ /* Not a regular file, we can't assume we know the file size */
+ if (prefix_len) {
+ clen = alen = prefix_len;
+ data = malloc(prefix_len);
+ if (!data)
+ goto err;
+
+ memcpy(data, prefix, prefix_len);
+ }
+
+ do {
+ alen += INCREMENTAL_CHUNK;
+ dp = realloc(data, alen);
+ if (!dp)
+ goto err;
+ data = dp;
+
+ rlen = fread((char *)data+clen, 1, alen-clen, f);
+ clen += rlen;
+ } while (clen == alen);
+
+ *len = clen;
+ xlen = (clen + LOADFILE_ZERO_PAD-1) & ~(LOADFILE_ZERO_PAD-1);
+ dp = realloc(data, xlen);
+ if (dp)
+ data = dp;
+ *ptr = data;
+ } else {
+ *len = clen = st.st_size + prefix_len - ftell(f);
+ xlen = (clen + LOADFILE_ZERO_PAD-1) & ~(LOADFILE_ZERO_PAD-1);
+
+ *ptr = data = malloc(xlen);
+ if ( !data )
+ return -1;
+
+ memcpy(data, prefix, prefix_len);
+
+ if ( (off_t)fread((char *)data+prefix_len, 1, clen-prefix_len, f)
+ != clen-prefix_len )
+ goto err;
+ }
+
+ memset((char *)data + clen, 0, xlen-clen);
+ return 0;
+
+ err:
+ if (data)
+ free(data);
+ return -1;
+}
diff --git a/com32/lib/syslinux/loadfile.c b/com32/lib/syslinux/loadfile.c
index ec7a6039..42a1fd61 100644
--- a/com32/lib/syslinux/loadfile.c
+++ b/com32/lib/syslinux/loadfile.c
@@ -2,11 +2,26 @@
*
* Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
*
- * 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
- * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
- * Boston MA 02111-1307, USA; either version 2 of the License, or
- * (at your option) any later version; incorporated herein by reference.
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*
* ----------------------------------------------------------------------- */
@@ -25,45 +40,19 @@
#include <syslinux/loadfile.h>
+#define INCREMENTAL_CHUNK 1024*1024
+
int loadfile(const char *filename, void **ptr, size_t *len)
{
- int fd;
- struct stat st;
- void *data;
FILE *f;
- size_t xlen;
+ int rv;
- fd = open(filename, O_RDONLY);
- if ( fd < 0 )
+ f = fopen(filename, "r");
+ if ( !f )
return -1;
- f = fdopen(fd, "rb");
- if ( !f ) {
- close(fd);
- return -1;
- }
-
- if ( fstat(fd, &st) )
- goto err_fclose;
-
- *len = st.st_size;
- xlen = (st.st_size + LOADFILE_ZERO_PAD-1) & ~(LOADFILE_ZERO_PAD-1);
-
- *ptr = data = malloc(xlen);
- if ( !data )
- goto err_fclose;
-
- if ( (off_t)fread(data, 1, st.st_size, f) != st.st_size )
- goto err_free;
-
- memset((char *)data + st.st_size, 0, xlen-st.st_size);
-
+ rv = floadfile(f, ptr, len, NULL, 0);
fclose(f);
- return 0;
- err_free:
- free(data);
- err_fclose:
- fclose(f);
- return -1;
+ return rv;
}
diff --git a/com32/lib/syslinux/zloadfile.c b/com32/lib/syslinux/zloadfile.c
new file mode 100644
index 00000000..8dff193e
--- /dev/null
+++ b/com32/lib/syslinux/zloadfile.c
@@ -0,0 +1,59 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2005-2008 H. Peter Anvin - All Rights Reserved
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall
+ * be included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * zloadfile.c
+ *
+ * Read the contents of a possibly compressed data file into a malloc'd buffer
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <syslinux/zio.h>
+
+#include <syslinux/loadfile.h>
+
+#define INCREMENTAL_CHUNK 1024*1024
+
+int zloadfile(const char *filename, void **ptr, size_t *len)
+{
+ FILE *f;
+ int rv;
+
+ f = zfopen(filename, "r");
+ if ( !f )
+ return -1;
+
+ rv = floadfile(f, ptr, len, NULL, 0);
+ fclose(f);
+
+ return rv;
+}
diff --git a/com32/modules/elf.c b/com32/modules/elf.c
index 772ee49a..9e4a18c7 100644
--- a/com32/modules/elf.c
+++ b/com32/modules/elf.c
@@ -281,7 +281,7 @@ int main(int argc, char *argv[])
return 1;
}
- if (loadfile(argv[1], &data, &data_len)) {
+ if (zloadfile(argv[1], &data, &data_len)) {
error("Unable to load file\n");
return 1;
}
diff --git a/com32/modules/mboot.c b/com32/modules/mboot.c
index 3d744256..6c3ce340 100644
--- a/com32/modules/mboot.c
+++ b/com32/modules/mboot.c
@@ -835,7 +835,7 @@ static void trampoline_start(section_t *secs, int sec_count,
/* asm bzero() code from com32/lib/memset.c */
char *q = (char *) secs[i].dest;
size_t nl = secs[i].size >> 2;
- asm volatile("cld ; rep ; stosl ; movl %3,%0 ; rep ; stosb"
+ asm volatile("rep ; stosl ; movl %3,%0 ; rep ; stosb"
: "+c" (nl), "+D" (q)
: "a" (0x0U), "r" (secs[i].size & 3));
} else {
@@ -844,12 +844,12 @@ static void trampoline_start(section_t *secs, int sec_count,
char *q = (char *) secs[i].dest;
size_t n = secs[i].size;
if ( q < p ) {
- asm volatile("cld ; rep ; movsb"
+ asm volatile("rep ; movsb"
: "+c" (n), "+S" (p), "+D" (q));
} else {
p += (n-1);
q += (n-1);
- asm volatile("std ; rep ; movsb"
+ asm volatile("std ; rep ; movsb ; cld"
: "+c" (n), "+S" (p), "+D" (q));
}
}
diff --git a/comboot.inc b/comboot.inc
index 3a9b4332..07ec352a 100644
--- a/comboot.inc
+++ b/comboot.inc
@@ -61,6 +61,7 @@
; Looks like a COMBOOT image but too large
comboot_too_large:
+ call close_file
mov si,err_comlarge
call cwritestr
jmp enter_command
@@ -71,11 +72,6 @@ comboot_too_large:
; do, however, allow the execution of INT 20h to return to SYSLINUX.
;
is_comboot_image:
- and dx,dx
- jnz comboot_too_large
- cmp ax,0ff00h ; Max size in bytes
- jae comboot_too_large
-
push si ; Save file handle
call make_plain_cmdline
@@ -126,9 +122,11 @@ is_comboot_image:
; Now actually load the file...
pop si ; File handle
mov bx,100h ; Load at <seg>:0100h
- mov cx,0FF00h >> SECTOR_SHIFT
+ mov cx,10000h >> SECTOR_SHIFT
; Absolute maximum # of sectors
call getfssec
+ cmp ecx,65536-256-2 ; Maximum size
+ ja comboot_too_large
; And invoke the program...
mov ax,es
@@ -409,8 +407,7 @@ comapi_open:
pop ds
call searchdir
jz comapi_err
- mov P_AX,ax
- mov P_HAX,dx
+ mov P_EAX,eax
mov P_CX,SECTOR_SIZE
mov P_SI,si
clc
@@ -428,6 +425,7 @@ comapi_read:
jnc .noteof
xor si,si ; SI <- 0 on EOF, CF <- 0
.noteof: mov P_SI,si
+ mov P_ECX,ecx
ret
;
@@ -698,8 +696,7 @@ comapi_runkernel:
; The kernel image was found, so we can load it...
mov [Kernel_SI],si
- mov [Kernel_EAX],ax
- mov [Kernel_EAX+2],dx
+ mov [Kernel_EAX],eax
; It's not just possible, but quite likely, that ES:BX
; points into real_mode_seg, so we need to exercise some
diff --git a/doc/comboot.txt b/doc/comboot.txt
index c4b0f076..42078ed5 100644
--- a/doc/comboot.txt
+++ b/doc/comboot.txt
@@ -293,7 +293,7 @@ AX=0006h [2.08] Open file
Input: AX 0006h
ES:SI null-terminated filename
Output: SI file handle
- EAX length of file in bytes
+ EAX length of file in bytes, or -1
CX file block size
Open a file for reading. The exact syntax of the filenames
@@ -304,6 +304,9 @@ AX=0006h [2.08] Open file
Note: SYSLINUX considers a zero-length file to be nonexistent.
+ In 3.70 or later, EAX can contain -1 indicating that the file
+ length is unknown.
+
AX=0007h [2.08] Read file
@@ -312,6 +315,7 @@ AX=0007h [2.08] Read file
ES:BX buffer
CX number of blocks to read
Output: SI file handle, or 0 if EOF was reached
+ ECX number of bytes read [3.70]
Read blocks from a file. Note that the file handle that is
returned in SI may not be the same value that was passed in.
@@ -319,6 +323,10 @@ AX=0007h [2.08] Read file
If end of file was reached (SI=0), the file was automatically
closed.
+ In 3.70 or later, ECX returns the number of bytes read. This
+ will always be a multiple of the block size unless EOF is
+ reached.
+
The address of the buffer (ES:BX) should be at least 512-byte
aligned. SYSLINUX guarantees at least this alignment for the
COMBOOT load segment or the COM32 bounce buffer.
diff --git a/extlinux.asm b/extlinux.asm
index 8b2eff5b..73c8bed5 100644
--- a/extlinux.asm
+++ b/extlinux.asm
@@ -85,7 +85,7 @@ comboot_seg equ real_mode_seg ; COMBOOT image loading zone
; File structure. This holds the information for each currently open file.
;
struc open_file_t
-file_left resd 1 ; Number of sectors left (0 = free)
+file_bytesleft resd 1 ; Number of bytes left (0 = free)
file_sector resd 1 ; Next linear sector to read
file_in_sec resd 1 ; Sector where inode lives
file_in_off resw 1
@@ -914,7 +914,7 @@ allocate_file:
; If successful:
; ZF clear
; SI = file pointer
-; DX:AX = EAX = file length in bytes
+; EAX = file length in bytes
; ThisInode = the first 128 bytes of the inode
; If unsuccessful
; ZF set
@@ -987,14 +987,8 @@ open_inode:
mov ax,[ThisInode+i_mode]
mov [bx+file_mode],ax
mov eax,[ThisInode+i_size]
- push eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [bx+file_left],eax
- pop eax
+ mov [bx+file_bytesleft],eax
mov si,bx
- mov edx,eax
- shr edx,16 ; 16-bitism, sigh
and eax,eax ; ZF clear unless zero-length file
pop gs
pop cx
@@ -1015,7 +1009,8 @@ ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
close_file:
and si,si
jz .closed
- mov dword [si],0 ; First dword == file_left
+ mov dword [si],0 ; First dword == file_bytesleft
+ xor si,si
.closed: ret
;
@@ -1437,6 +1432,7 @@ linsector:
; CX -> Sector count (0FFFFh = until end of file)
; Must not exceed the ES segment
; Returns CF=1 on EOF (not necessarily error)
+; On return ECX = number of bytes read
; All arguments are advanced to reflect data read.
;
getfssec:
@@ -1446,9 +1442,13 @@ getfssec:
push edi
movzx ecx,cx
- cmp ecx,[si] ; Number of sectors left
+ push ecx ; Sectors requested read
+ mov eax,[si+file_bytesleft]
+ add eax,SECTOR_SIZE-1
+ shr eax,SECTOR_SHIFT
+ cmp ecx,eax ; Number of sectors left
jbe .lenok
- mov cx,[si]
+ mov cx,ax
.lenok:
.getfragment:
mov eax,[si+file_sector] ; Current start index
@@ -1487,12 +1487,18 @@ getfssec:
add bx,bp ; Adjust buffer pointer
pop bp
add [si+file_sector],ebp ; Next sector index
- sub [si],ebp ; Sectors consumed
jcxz .done
jnz .getfragment
; Fall through
.done:
- cmp dword [si],1 ; Did we run out of file?
+ pop ecx ; Sectors requested read
+ shl ecx,SECTOR_SHIFT
+ cmp ecx,[si+file_bytesleft]
+ jb .noteof
+ mov ecx,[si+file_bytesleft]
+.noteof: sub [si+file_bytesleft],ecx
+ ; Did we run out of file?
+ cmp dword [si+file_bytesleft],1
; CF set if [SI] < 1, i.e. == 0
pop edi
pop edx
diff --git a/font.inc b/font.inc
index 8847d15c..be9a365c 100644
--- a/font.inc
+++ b/font.inc
@@ -21,12 +21,14 @@
;
; loadfont: Load a .psf font file and install it onto the VGA console
; (if we're not on a VGA screen then ignore.) It is called with
-; SI and DX:AX set by routine searchdir
+; SI and EAX set by routine searchdir
;
loadfont:
- mov bx,trackbuf ; The trackbuf is >= 16K; the part
- mov cx,[BufSafe] ; of a PSF file we care about is no
- call getfssec ; more than 8K+4 bytes
+ ; XXX: This can be 8K+4 bytes and the trackbuf is only
+ ; guaranteed to be 8K in size...
+ mov bx,trackbuf
+ mov cx,[BufSafe]
+ call getfssec
mov ax,[trackbuf] ; Magic number
cmp ax,0436h
diff --git a/getc.inc b/getc.inc
index 275c0fab..b36115ca 100644
--- a/getc.inc
+++ b/getc.inc
@@ -23,12 +23,11 @@ MAX_GETC equ (1 << MAX_GETC_LG2)
bytes_per_getc_lg2 equ 16-MAX_GETC_LG2
bytes_per_getc equ (1 << bytes_per_getc_lg2)
secs_per_getc equ bytes_per_getc/SECTOR_SIZE
-MAX_UNGET equ 5 ; Max bytes that can be pushed back
+MAX_UNGET equ 9 ; Max bytes that can be pushed back
struc getc_file
gc_file resw 1 ; File pointer
gc_bufbytes resw 1 ; Bytes left in buffer
-gc_bytes resd 1 ; Bytes left in file
gc_bufdata resw 1 ; Pointer to data in buffer
gc_unget_cnt resb 1 ; Character pushed back count
gc_unget_buf resb MAX_UNGET ; Character pushed back buffer
@@ -52,7 +51,7 @@ getc_file_lg2 equ 4 ; Size of getc_file as a power of 2
; open: Input: mangled filename in DS:DI
; Output: ZF set on file not found or zero length
;
-; openfd: Input: file handle in SI
+; openfd: Input: file handle in SI, file size in EAX
; Output: ZF set on getc stack overflow
;
; getc: Output: CF set on end of file
@@ -73,8 +72,6 @@ openfd:
mov [CurrentGetC],bx
mov [bx+gc_file],si ; File pointer
- mov [bx+gc_bytes],ax ; Bytes available
- mov [bx+gc_bytes+2],dx
xor ax,ax
mov [bx+gc_bufbytes],ax ; Buffer empty
mov [bx+gc_unget_cnt],al ; ungetc buffer empty
@@ -133,27 +130,22 @@ getc:
mov [di+gc_bufdata],bx
mov si,[di+gc_file]
- mov ecx,[di+gc_bytes]
- jecxz .empty
- cmp ecx,bytes_per_getc
- jna .sizeok
- mov ecx,bytes_per_getc
-.sizeok:
- mov [di+gc_bufbytes],cx
- sub [di+gc_bytes],ecx
- add cx,SECTOR_SIZE-1
- shr cx,SECTOR_SHIFT
+ and si,si
+ mov [di+gc_bufbytes],si ; In case SI == 0
+ jz .empty
+ mov cx,bytes_per_getc >> SECTOR_SHIFT
call getfssec
+ mov [di+gc_bufbytes],cx
mov [di+gc_file],si
+ jcxz .empty
popad
+ TRACER 'd'
jmp .got_data
.empty:
- ; CX == 0 at this point; gc_bufbytes was clobbered
- ; by the subtract; we need to restore it to zero so
- ; we will continue to get EOF on any further attempts
- ; to read the file.
- mov [di+gc_bufbytes],cx
+ TRACER 'e'
+ ; [di+gc_bufbytes] is zero already, thus we will continue
+ ; to get EOF on any further attempts to read the file.
popad
xor al,al ; Return a predictable zero
stc
diff --git a/isolinux.asm b/isolinux.asm
index c2457697..42935645 100644
--- a/isolinux.asm
+++ b/isolinux.asm
@@ -76,7 +76,9 @@ comboot_seg equ real_mode_seg ; COMBOOT image loading zone
;
struc open_file_t
file_sector resd 1 ; Sector pointer (0 = structure free)
+file_bytesleft resd 1 ; Number of bytes left
file_left resd 1 ; Number of sectors left
+ resd 1 ; Unused
endstruc
%ifndef DEPEND
@@ -105,7 +107,7 @@ trackbuf resb trackbufsize ; Track buffer goes here
; Some of these are touched before the whole image
; is loaded. DO NOT move this to .uibss.
- section .bss1
+ section .bss2
alignb 4
ISOFileName resb 64 ; ISO filename canonicalization buffer
ISOFileNameEnd equ $
@@ -961,8 +963,8 @@ load_config:
%include "ui.inc"
;
-; Enable disk emulation. The kind of disk we emulate is dependent on the size of
-; the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
+; Enable disk emulation. The kind of disk we emulate is dependent on the
+; size of the file: 1200K, 1440K or 2880K floppy, otherwise harddisk.
;
is_disk_image:
TRACER CR
@@ -970,8 +972,7 @@ is_disk_image:
TRACER 'D'
TRACER ':'
- shl edx,16
- mov dx,ax ; Set EDX <- file size
+ mov edx,eax ; File size
mov di,img_table
mov cx,img_table_count
mov eax,[si+file_sector] ; Starting LBA of file
@@ -1140,6 +1141,7 @@ close_file:
and si,si
jz .closed
mov dword [si],0 ; First dword == file_left
+ xor si,si
.closed: ret
;
@@ -1152,7 +1154,7 @@ close_file:
; If successful:
; ZF clear
; SI = file pointer
-; DX:AX or EAX = file length in bytes
+; EAX = file length in bytes
; If unsuccessful
; ZF set
;
@@ -1264,13 +1266,12 @@ searchdir_iso:
mov eax,[si+2] ; Location of extent
mov [bx+file_sector],eax
mov eax,[si+10] ; Data length
+ mov [bx+file_bytesleft],eax
push eax
add eax,SECTOR_SIZE-1
shr eax,SECTOR_SHIFT
mov [bx+file_left],eax
pop eax
- mov edx,eax
- shr edx,16
and bx,bx ; ZF = 0
mov si,bx
pop es
@@ -1432,6 +1433,7 @@ unmangle_name: call strcpy
; On exit:
; SI -> File pointer (or 0 on EOF)
; CF = 1 -> Hit EOF
+; ECX -> Bytes actually read
;
getfssec:
TRACER 'F'
@@ -1444,8 +1446,8 @@ getfssec:
cmp ecx,[si+file_left]
jna .ok_size
mov ecx,[si+file_left]
-.ok_size:
+.ok_size:
mov bp,cx
push cx
push si
@@ -1459,13 +1461,24 @@ getfssec:
add [si+file_sector],ecx
sub [si+file_left],ecx
ja .not_eof ; CF = 0
-
- xor ecx,ecx
- mov [si+file_sector],ecx ; Mark as unused
- xor si,si
stc
.not_eof:
+ pushf
+ shl ecx,SECTOR_SHIFT ; Convert to bytes
+ cmp ecx,[si+file_bytesleft]
+ jb .not_all
+ mov ecx,[si+file_bytesleft]
+.not_all: sub [si+file_bytesleft],ecx
+ popf
+ jnc .ret
+ push eax
+ xor eax,eax
+ mov [si+file_sector],eax ; Unused
+ mov si,ax
+ pop eax
+ stc
+.ret:
pop ds
TRACER 'f'
ret
diff --git a/kernel.inc b/kernel.inc
index ecf6698a..0da03638 100644
--- a/kernel.inc
+++ b/kernel.inc
@@ -56,10 +56,10 @@ su_heapend resw 1 ; 0224
su_pad1 resw 1 ; 0226
su_cmd_line_ptr resd 1 ; 0228
su_ramdisk_max resd 1 ; 022C
- resb (0e000h-12)-($-$$) ; Were bootsect.S puts it...
-linux_stack equ $ ; DFF4
+ resb (0f800h-12)-($-$$)
+linux_stack equ $ ; F7F4
linux_fdctab resb 12
-cmd_line_here equ $ ; E000 Should be out of the way
+cmd_line_here equ $ ; F800 Should be out of the way
endstruc
;
@@ -72,6 +72,7 @@ CMD_MAGIC equ 0A33Fh ; Command line magic
; heap.
;
old_cmd_line_here equ 9800h
+old_max_cmd_len equ 2047
old_linux_fdctab equ old_cmd_line_here-12
old_linux_stack equ old_linux_fdctab
diff --git a/ldlinux.asm b/ldlinux.asm
index 0f063154..b12403eb 100644
--- a/ldlinux.asm
+++ b/ldlinux.asm
@@ -88,7 +88,9 @@ comboot_seg equ real_mode_seg ; COMBOOT image loading zone
;
struc open_file_t
file_sector resd 1 ; Sector pointer (0 = structure free)
+file_bytesleft resd 1 ; Number of bytes left
file_left resd 1 ; Number of sectors left
+ resd 1 ; Unused
endstruc
%ifndef DEPEND
@@ -1032,7 +1034,8 @@ search_dos_dir:
close_file:
and si,si
jz .closed
- mov dword [si],0 ; First dword == file_left
+ mov dword [si],0 ; First dword == file_sector
+ xor si,si
.closed: ret
;
@@ -1045,7 +1048,7 @@ close_file:
; If successful:
; ZF clear
; SI = file pointer
-; DX:AX or EAX = file length in bytes
+; EAX = file length in bytes
; If unsuccessful
; ZF set
;
@@ -1089,8 +1092,12 @@ searchdir:
jnz .badfile ; If not a file, it's a bad thing
; SI and EAX are already set
- mov edx,eax
- shr edx,16 ; Old 16-bit remnant...
+ mov [si+file_bytesleft],eax
+ push eax
+ add eax,SECTOR_SIZE-1
+ shr eax,SECTOR_SHIFT
+ mov [si+file_left],eax ; Sectors left
+ pop eax
and eax,eax ; EAX != 0
jz .badfile
ret ; Done!
@@ -1110,7 +1117,6 @@ searchdir:
.notfound:
xor eax,eax
- xor dx,dx
ret
section .bss
@@ -1344,22 +1350,36 @@ getfssec_edx:
; CX -> Sector count (0FFFFh = until end of file)
; Must not exceed the ES segment
; Returns CF=1 on EOF (not necessarily error)
+; ECX returns number of bytes read.
; All arguments are advanced to reflect data read.
;
getfssec:
push edx
movzx edx,cx
- cmp edx,[si+4]
+ push edx ; Zero-extended CX
+ cmp edx,[si+file_left]
jbe .sizeok
- mov edx,[si+4]
+ mov edx,[si+file_left]
mov cx,dx
.sizeok:
- sub [si+4],edx
- mov edx,[si]
+ sub [si+file_left],edx
+ mov edx,[si+file_sector]
call getfssec_edx
- mov [si],edx
+ mov [si+file_sector],edx
+ pop ecx ; Sectors requested read
+ shl ecx,SECTOR_SHIFT
+ cmp ecx,[si+file_bytesleft]
+ ja .eof
+.noteof:
+ sub [si+file_bytesleft],ecx ; CF <- 0
pop edx
ret
+.eof:
+ mov ecx,[si+file_bytesleft]
+ call close_file
+ pop edx
+ stc
+ ret
;
; nextcluster: Advance a cluster pointer in EDI to the next cluster
diff --git a/loadhigh.inc b/loadhigh.inc
index b2e87f23..63041483 100644
--- a/loadhigh.inc
+++ b/loadhigh.inc
@@ -25,30 +25,35 @@
;
; The xfer_buf_seg is used as a bounce buffer.
;
+; Assumes CS == DS.
+;
; The input address (EDI) should be dword aligned, and the final
; stretch is padded with zeroes if necessary.
;
; Inputs: SI = file handle/cluster pointer
; EDI = target address in high memory
-; EAX = size of remaining file in bytes
+; EAX = maximum number of bytes to load
; DX = zero-padding mask (e.g. 0003h for pad to dword)
; BX = subroutine to call at the top of each loop
; (to print status and check for abort)
+; MyHighMemSize = maximum load address
;
; Outputs: SI = file handle/cluster pointer
-; EDI = first untouched address (not including padding)
+; EBX = first untouched address (not including padding)
+; EDI = first untouched address (including padding)
+; CF = reached EOF
;
load_high:
push es ; <AAA> ES
mov cx,xfer_buf_seg
mov es,cx
+ mov [PauseBird],bx
.read_loop:
and si,si ; If SI == 0 then we have end of file
jz .eof
- call bx
- push bx ; <AA> Pausebird function
+ call [PauseBird]
push eax ; <A> Total bytes to transfer
cmp eax,(1 << 16) ; Max 64K in one transfer
@@ -65,38 +70,51 @@ load_high:
xor bx,bx ; ES:0
call getfssec ; Load the data into xfer_buf_seg
pop edi ; <C> Target buffer
- pop ecx ; <B> Byte count this round
- push ecx ; <B> Byte count this round
- push edi ; <C> Target buffer
+ pushf ; <C> EOF status
+ lea ebx,[edi+ecx] ; End of data
.fix_slop:
test cx,dx
jz .noslop
; The last dword fractional - pad with zeroes
; Zero-padding is critical for multi-file initramfs.
mov byte [es:ecx],0
- inc ecx
+ inc cx
jmp short .fix_slop
.noslop:
+ lea eax,[edi+ecx]
+ cmp eax,[MyHighMemSize]
+ ja .overflow
+
push esi ; <D> File handle/cluster pointer
mov esi,(xfer_buf_seg << 4) ; Source address
call bcopy ; Copy to high memory
pop esi ; <D> File handle/cluster pointer
- pop edi ; <C> Target buffer
+ popf ; <C> EOF status
pop ecx ; <B> Byte count this round
pop eax ; <A> Total bytes to transfer
- add edi,ecx
+ jc .eof
sub eax,ecx
- pop bx ; <AA> Pausebird function
- jnz .read_loop ; More to read...
-
-
+ jnz .read_loop ; More to read... (if ZF=1 then CF=0)
.eof:
pop es ; <AAA> ES
ret
+.overflow: mov si,err_nohighmem
+ jmp abort_load
+
dot_pause:
push ax
mov al,'.'
call writechr
pop ax
jmp abort_check ; Handles the return
+
+ section .data
+err_nohighmem db CR, LF
+ db 'Not enough memory to load specified image.', CR, LF, 0
+
+ section .bss
+ alignb 2
+PauseBird resw 1
+
+ section .text
diff --git a/ppmtolss16 b/ppmtolss16
index a63e0a2a..5af90831 100755
--- a/ppmtolss16
+++ b/ppmtolss16
@@ -25,9 +25,9 @@
##
## N ... if N is != previous pixel, one pixel of color N
## ... otherwise run sequence follows ...
-## M ... if M > 0 then run length is M+1
+## M ... if M > 0 then run length is M
## ... otherwise run sequence is encoded in two nybbles,
-## littleendian, +17
+## littleendian, +16
##
## The nybble sequences are on a per-row basis; runs may not extend
## across rows and odd-nybble rows are zero-padded.
diff --git a/pxelinux.asm b/pxelinux.asm
index 2f08bac5..ba9c6e19 100644
--- a/pxelinux.asm
+++ b/pxelinux.asm
@@ -165,7 +165,8 @@ tftp_blksize resd 1 ; Block size for this connection(*)
tftp_bytesleft resw 1 ; Unclaimed data bytes
tftp_lastpkt resw 1 ; Sequence number of last packet (NBO)
tftp_dataptr resw 1 ; Pointer to available data
- resw 2 ; Currently unusued
+tftp_goteof resb 1 ; 1 if the EOF packet received
+ resb 3 ; Currently unusued
; At end since it should not be zeroed on socked close
tftp_pktbuf resw 1 ; Packet buffer offset
endstruc
@@ -1037,7 +1038,7 @@ close_file:
; If successful:
; ZF clear
; SI = socket pointer
-; DX:AX = file length in bytes
+; EAX = file length in bytes, or -1 if unknown
; If unsuccessful
; ZF set
;
@@ -1152,8 +1153,10 @@ searchdir:
mov si,[bp-6] ; TFTP pointer
mov bx,[bp-8] ; TID
+ ; Make sure the packet actually came from the server
+ ; This is technically not to the TFTP spec?
mov eax,[si+tftp_remoteip]
- cmp [pxe_udp_read_pkt.sip],eax ; This is technically not to the TFTP spec?
+ cmp [pxe_udp_read_pkt.sip],eax
jne .no_packet
; Got packet - reset timeout
@@ -1170,7 +1173,7 @@ searchdir:
; Default blksize unless blksize option negotiated
mov word [si+tftp_blksize], TFTP_BLOCKSIZE
- mov cx,[pxe_udp_read_pkt.buffersize]
+ movzx ecx,word [pxe_udp_read_pkt.buffersize]
sub cx,2 ; CX <- bytes after opcode
jb .failure ; Garbled reply
@@ -1180,13 +1183,21 @@ searchdir:
cmp ax, TFTP_ERROR
je .bailnow ; ERROR reply: don't try again
+ ; If the server doesn't support any options, we'll get
+ ; a DATA reply instead of OACK. Stash the data in
+ ; the file buffer and go with the default value for
+ ; all options...
+ cmp ax, TFTP_DATA
+ je .no_oack
+
cmp ax, TFTP_OACK
- jne .no_tsize
+ jne .err_reply ; Unknown packet type
; Now we need to parse the OACK packet to get the transfer
- ; size. SI -> first byte of options; CX -> byte count
+ ; and packet sizes.
+ ; SI -> first byte of options; [E]CX -> byte count
.parse_oack:
- jcxz .no_tsize ; No options acked
+ jcxz .done_pkt ; No options acked
.get_opt_name:
mov di,si
mov bx,si
@@ -1256,11 +1267,6 @@ searchdir:
pop si ; We want the packet ptr in SI
mov eax,[si+tftp_filesize]
- cmp eax,-1
- jz .no_tsize
- mov edx,eax
- shr edx,16 ; DX:AX == EAX
-
and eax,eax ; Set ZF depending on file size
pop bp ; Junk
pop bp ; Junk (retry counter)
@@ -1272,7 +1278,43 @@ searchdir:
pop es
ret
-.no_tsize:
+
+.no_oack: ; We got a DATA packet, meaning no options are
+ ; suported. Save the data away and consider the length
+ ; undefined, *unless* this is the only data packet...
+ mov bx,[bp-6] ; File pointer
+ sub cx,2 ; Too short?
+ jb .failure
+ lodsw ; Block number
+ cmp ax,htons(1)
+ jne .failure
+ mov [bx+tftp_lastpkt],ax
+ cmp cx,TFTP_BLOCKSIZE
+ ja .err_reply ; Corrupt...
+ je .not_eof
+ ; This was the final EOF packet, already...
+ ; We know the filesize, but we also want to ack the
+ ; packet and set the EOF flag.
+ mov [bx+tftp_filesize],ecx
+ mov byte [bx+tftp_goteof],1
+ push si
+ mov si,bx
+ ; AX = htons(1) already
+ call ack_packet
+ pop si
+.not_eof:
+ mov [bx+tftp_bytesleft],cx
+ mov ax,pktbuf_seg
+ push es
+ mov es,ax
+ mov di,tftp_pktbuf
+ mov [bx+tftp_dataptr],di
+ add cx,3
+ shr cx,2
+ rep movsd
+ pop es
+ jmp .done_pkt
+
.err_reply: ; Option negotiation error. Send ERROR reply.
; ServerIP and gateway are already programmed in
mov si,[bp-6]
@@ -1285,7 +1327,7 @@ searchdir:
call pxenv
; Write an error message and explode
- mov si,err_oldtftp
+ mov si,err_damage
call writestr
jmp kaboom
@@ -1572,83 +1614,106 @@ PXEEntry equ pxe_thunk.jump+1
; On exit:
; SI -> TFTP socket pointer (or 0 on EOF)
; CF = 1 -> Hit EOF
+; ECX -> number of bytes actually read
;
-getfssec: push si
+getfssec: push eax
+ push edi
+ push bx
+ push si
push fs
mov di,bx
- mov bx,si
mov ax,pktbuf_seg
mov fs,ax
+ xor eax,eax
movzx ecx,cx
shl ecx,TFTP_BLOCKSIZE_LG2 ; Convert to bytes
+ push ecx ; Initial request size
jz .hit_eof ; Nothing to do?
.need_more:
- push ecx
+ call fill_buffer
+ movzx eax,word [si+tftp_bytesleft]
+ and ax,ax
+ jz .hit_eof
- movzx eax,word [bx+tftp_bytesleft]
+ push ecx
cmp ecx,eax
jna .ok_size
mov ecx,eax
- jcxz .need_packet ; No bytes available?
.ok_size:
-
mov ax,cx ; EAX<31:16> == ECX<31:16> == 0
- mov si,[bx+tftp_dataptr]
- sub [bx+tftp_bytesleft],cx
+ mov bx,[si+tftp_dataptr]
+ sub [si+tftp_bytesleft],cx
+ xchg si,bx
fs rep movsb ; Copy from packet buffer
- mov [bx+tftp_dataptr],si
+ xchg si,bx
+ mov [si+tftp_dataptr],bx
pop ecx
sub ecx,eax
jnz .need_more
-
.hit_eof:
+ call fill_buffer
+
+ pop eax ; Initial request amount
+ xchg eax,ecx
+ sub ecx,eax ; ... minus anything not gotten
+
pop fs
pop si
; Is there anything left of this?
mov eax,[si+tftp_filesize]
sub eax,[si+tftp_filepos]
- jnz .bytes_left ; CF <- 0
+ jnz .bytes_left
- cmp [si+tftp_bytesleft],ax
- jnz .bytes_left ; CF <- 0
+ cmp [si+tftp_bytesleft],ax ; AX == 0
+ jne .bytes_left
+ cmp byte [si+tftp_goteof],0
+ je .done
+ ; I'm 99% sure this can't happen, but...
+ call fill_buffer ; Receive/ACK the EOF packet
+.done:
; The socket is closed and the buffer drained
; Close socket structure and re-init for next user
call free_socket
stc
+ jmp .ret
.bytes_left:
+ clc
+.ret:
+ pop bx
+ pop edi
+ pop eax
ret
;
-; No data in buffer, check to see if we can get a packet...
+; Get a fresh packet if the buffer is drained, and we haven't hit
+; EOF yet. The buffer should be filled immediately after draining!
;
-.need_packet:
- pop ecx
- mov eax,[bx+tftp_filesize]
- cmp eax,[bx+tftp_filepos]
- je .hit_eof ; Already EOF'd; socket already closed
+; expects fs -> pktbuf_seg and ds:si -> socket structure
+;
+fill_buffer:
+ cmp word [si+tftp_bytesleft],0
+ je .empty
+ ret ; Otherwise, nothing to do
- pushad
+.empty:
push es
- mov si,bx
- call get_packet
- pop es
- popad
-
- jmp .need_more
-
-;
-; Get a fresh packet; expects fs -> pktbuf_seg and ds:si -> socket structure
-;
-get_packet:
+ pushad
mov ax,ds
mov es,ax
+ ; Note: getting the EOF packet is not the same thing
+ ; as tftp_filepos == tftp_filesize; if the EOF packet
+ ; is empty the latter condition can be true without
+ ; having gotten the official EOF.
+ cmp byte [si+tftp_goteof],0
+ jne .ret ; Alread EOF
+
.packet_loop:
; Start by ACKing the previous packet; this should cause the
; next packet to be sent.
@@ -1730,7 +1795,8 @@ get_packet:
call ack_packet
jmp .send_ok ; Reset timeout
-.right_packet: ; It's the packet we want. We're also EOF if the size < blocksize
+.right_packet: ; It's the packet we want. We're also EOF if the
+ ; size < blocksize
pop cx ; <D> Don't need the retry count anymore
@@ -1739,10 +1805,6 @@ get_packet:
movzx ecx,word [pxe_udp_read_pkt.buffersize]
sub cx,byte 4 ; Skip TFTP header
- ; If this is a zero-length block, don't mess with the pointers,
- ; since we may have just set up the previous block that way
- jz .last_block
-
; Set pointer to data block
lea ax,[bx+4] ; Data past TFTP header
mov [si+tftp_dataptr],ax
@@ -1751,27 +1813,25 @@ get_packet:
mov [si+tftp_bytesleft],cx
cmp cx,[si+tftp_blksize] ; Is it a full block?
- jb .last_block ; If so, it's not EOF
-
- ; If we had the exact right number of bytes, always get
- ; one more packet to get the (zero-byte) EOF packet and
- ; close the socket.
- mov eax,[si+tftp_filepos]
- cmp [si+tftp_filesize],eax
- je .packet_loop
+ jb .last_block ; If not, it's EOF
+.ret:
+ popad
+ pop es
ret
.last_block: ; Last block - ACK packet immediately
+ TRACER 'L'
mov ax,[fs:bx+2]
call ack_packet
; Make sure we know we are at end of file
mov eax,[si+tftp_filepos]
mov [si+tftp_filesize],eax
+ mov byte [si+tftp_goteof],1
- ret
+ jmp .ret
;
; ack_packet:
@@ -2446,7 +2506,7 @@ err_nopxe db "No !PXE or PXENV+ API found; we're dead...", CR, LF, 0
err_pxefailed db 'PXE API call failed, error ', 0
err_udpinit db 'Failed to initialize UDP stack', CR, LF, 0
err_noconfig db 'Unable to locate configuration file', CR, LF, 0
-err_oldtftp db 'TFTP server does not support the tsize option', CR, LF, 0
+err_damage db 'TFTP server sent an incomprehesible reply', CR, LF, 0
found_pxenv db 'Found PXENV+ structure', CR, LF, 0
using_pxenv_msg db 'Old PXE API detected, using PXENV+ structure', CR, LF, 0
apiver_str db 'PXE API version is ',0
diff --git a/runkernel.inc b/runkernel.inc
index 98d826f0..5cabbef8 100644
--- a/runkernel.inc
+++ b/runkernel.inc
@@ -45,65 +45,38 @@
; obsolete.
;
is_linux_kernel:
- and dx,dx
- jnz kernel_sane
- cmp ax,1024 ; Bootsect + 1 setup sect
- jb kernel_corrupt
-kernel_sane: push ax
- push dx
- push si
+ push si ; <A> file pointer
mov si,loading_msg
call cwritestr
+ mov si,KernelCName ; Print kernel name part of
+ call cwritestr ; "Loading" message
+
+
;
; Now start transferring the kernel
;
push word real_mode_seg
pop es
- movzx eax,ax ; Fix this by using a 32-bit
- shl edx,16 ; register for the kernel size
- or eax,edx
- mov [KernelSize],eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [KernelSects],eax ; Total sectors in kernel
-
-;
-; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
-; have to see if we're loading more than 64K, and if so, load it step by
-; step.
-;
-
;
; Start by loading the bootsector/setup code, to see if we need to
; do something funky. It should fit in the first 32K (loading 64K won't
; work since we might have funny stuff up near the end of memory).
-; If we have larger than 32K clusters, yes, we're hosed.
-;
- call abort_check ; Check for abort key
- mov ecx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
- cmp ecx,[KernelSects]
- jna .normalkernel
- mov ecx,[KernelSects]
-.normalkernel:
- sub [KernelSects],ecx
+;
+ call dot_pause ; Check for abort key
+ mov cx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
xor bx,bx
- pop si ; Cluster pointer on stack
+ pop si ; <A> file pointer
call getfssec
+ cmp cx,1024
+ jb kernel_corrupt
cmp word [es:bs_bootsign],0AA55h
jne kernel_corrupt ; Boot sec signature missing
;
-; Save the cluster pointer for later...
-;
- push si
-
-;
-; Initialize our end of memory pointer
+; Save the file pointer for later...
;
- mov eax,[HighMemRsvd]
- xor ax,ax ; Align to a 64K boundary
- mov [MyHighMemSize],eax
+ push si ; <A> file pointer
;
; Construct the command line (append options have already been copied)
@@ -155,7 +128,7 @@ get_next_opt: lodsb
or byte [cs:KeepPXE],1
.notkeep:
%endif
- push es ; Save ES -> real_mode_seg
+ push es ; <B> ES -> real_mode_seg
push cs
pop es ; Set ES <- normal DS
mov di,initrd_cmd
@@ -170,7 +143,7 @@ get_next_opt: lodsb
.noramdisk:
xor ax,ax
mov [cs:InitRDPtr],ax
-.not_initrd: pop es ; Restore ES -> real_mode_seg
+.not_initrd: pop es ; <B> ES -> real_mode_seg
skip_this_opt: lodsb ; Load from command line
cmp al,' '
ja skip_this_opt
@@ -242,6 +215,16 @@ new_kernel:
;
mov al,[es:su_loadflags]
mov [LoadFlags],al
+
+ ; Cap the ramdisk memory range if appropriate
+ mov eax,[RamdiskMax]
+ cmp eax,[MyHighMemSize]
+ ja .ok
+ mov [MyHighMemSize],eax
+.ok:
+
+any_kernel:
+
;
; Load the kernel. We always load it at 100000h even if we're supposed to
; load it "low"; for a "low" load we copy it down to low memory right before
@@ -253,46 +236,33 @@ read_kernel:
jnz .sects_ok
mov al,4 ; 0 = 4 setup sectors
.sects_ok:
+ inc ax ; Including the boot sector
mov [SetupSecs],ax
- mov si,KernelCName ; Print kernel name part of
- call cwritestr ; "Loading" message
- mov si,dotdot_msg ; Print dots
- call cwritestr
+ call dot_pause
- mov eax,[MyHighMemSize]
- sub eax,100000h ; Load address
- cmp eax,[KernelSize]
- jb no_high_mem ; Not enough high memory
;
; Move the stuff beyond the setup code to high memory at 100000h
;
movzx esi,word [SetupSecs] ; Setup sectors
- inc si ; plus 1 boot sector
shl si,9 ; Convert to bytes
mov ecx,8000h ; 32K
sub ecx,esi ; Number of bytes to copy
- push ecx
add esi,(real_mode_seg << 4) ; Pointer to source
mov edi,100000h ; Copy to address 100000h
call bcopy ; Transfer to high memory
- ; On exit EDI -> where to load the rest
-
- mov si,dot_msg ; Progress report
- call cwritestr
- call abort_check
+ pop si ; <A> File pointer
+ and si,si ; EOF already?
+ jz high_load_done
- pop ecx ; Number of bytes in the initial portion
- pop si ; Restore file handle/cluster pointer
- mov eax,[KernelSize]
- sub eax,8000h ; Amount of kernel not yet loaded
- jbe high_load_done ; Zero left (tiny kernel)
+ ; On exit EDI -> where to load the rest
- xor dx,dx ; No padding needed
- mov bx,dot_pause ; Print dots...
- call load_high ; Copy the file
+ mov bx,dot_pause
+ or eax,-1 ; Load the whole file
+ mov dx,3 ; Pad to dword
+ call load_high
high_load_done:
mov [KernelEnd],edi
@@ -301,6 +271,19 @@ high_load_done:
mov si,dot_msg
call cwritestr
+;
+; Some older kernels (1.2 era) would have more than 4 setup sectors, but
+; would not rely on the boot protocol to manage that. These kernels fail
+; if they see protected-mode kernel data after the setup sectors, so
+; clear that memory.
+;
+ mov di,[SetupSecs]
+ shl di,9
+ xor eax,eax
+ mov cx,cmd_line_here
+ sub cx,di
+ shr cx,2
+ rep stosd
;
; Now see if we have an initial RAMdisk; if so, do requisite computation
@@ -308,10 +291,12 @@ high_load_done:
; if we tried to load initrd using an old kernel
;
load_initrd:
- cmp word [InitRDPtr],0
- jz nk_noinitrd
+ xor eax,eax
+ cmp [InitRDPtr],ax
+ jz .noinitrd
call parse_load_initrd
-nk_noinitrd:
+.noinitrd:
+
;
; Abandon hope, ye that enter here! We do no longer permit aborts.
;
@@ -320,8 +305,6 @@ nk_noinitrd:
mov si,ready_msg
call cwritestr
- call vgaclearmode ; We can't trust ourselves after this
-
UNLOAD_PREP ; Module-specific hook
;
@@ -334,24 +317,34 @@ nk_noinitrd:
mov fs,ax
;
+; If the default root device is set to FLOPPY (0000h), change to
+; /dev/fd0 (0200h)
+;
+ cmp word [es:bs_rootdev],byte 0
+ jne root_not_floppy
+ mov word [es:bs_rootdev],0200h
+root_not_floppy:
+
+;
; Copy command line. Unfortunately, the old kernel boot protocol requires
; the command line to exist in the 9xxxxh range even if the rest of the
; setup doesn't.
;
setup_command_line:
- cli ; In case of hooked interrupts
mov dx,[KernelVersion]
test byte [LoadFlags],LOAD_HIGH
- jz need_high_cmdline
+ jz .need_high_cmdline
cmp dx,0202h ; Support new cmdline protocol?
- jb need_high_cmdline
+ jb .need_high_cmdline
; New cmdline protocol
; Store 32-bit (flat) pointer to command line
; This is the "high" location, since we have bzImage
mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4)+cmd_line_here
- jmp in_proper_place
+ mov word [HeapEnd],linux_stack
+ mov word [fs:su_heapend],linux_stack-512
+ jmp .setup_done
-need_high_cmdline:
+.need_high_cmdline:
;
; Copy command line down to fit in high conventional memory
; -- this happens if we have a zImage kernel or the protocol
@@ -373,7 +366,7 @@ need_high_cmdline:
; because we have a zImage, so we anticipate the move
; to 90000h already...
mov dword [fs:su_cmd_line_ptr],0x90000+old_cmd_line_here
- mov ax,4095 ; 2.02+ allow a higher limit
+ mov ax,old_max_cmd_len ; 2.02+ allow a higher limit
.adjusted:
mov cx,[CmdLineLen]
@@ -383,112 +376,112 @@ need_high_cmdline:
.len_ok:
fs rep movsb
stosb ; Final null, note AL=0 already
+ mov [CmdLineEnd],di
cmp dx,0200h
jb .nomovesize
mov [es:su_movesize],di ; Tell the kernel what to move
.nomovesize:
-
- test byte [LoadFlags],LOAD_HIGH
- jnz in_proper_place ; If high load, we're done
+.setup_done:
;
-; Loading low; we can't assume it's safe to run in place.
-;
-; Copy real_mode stuff up to 90000h
-;
- mov ax,9000h
- mov es,ax
- mov cx,di ; == su_movesize (from above)
- add cx,3 ; Round up
- shr cx,2 ; Convert to dwords
- xor si,si
- xor di,di
- fs rep movsd ; Copy setup + boot sector
-;
-; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
-; setup sectors, but the boot protocol had not yet been defined. They
-; rely on a signature to figure out if they need to copy stuff from
-; the "protected mode" kernel area. Unfortunately, we used that area
-; as a transfer buffer, so it's going to find the signature there.
-; Hence, zero the low 32K beyond the setup area.
-;
- mov di,[SetupSecs]
- inc di ; Setup + boot sector
- mov cx,32768/512 ; Sectors/32K
- sub cx,di ; Remaining sectors
- shl di,9 ; Sectors -> bytes
- shl cx,7 ; Sectors -> dwords
- xor eax,eax
- rep stosd ; Clear region
+; Time to start setting up move descriptors
;
-; Copy the kernel down to the "low" location (the kernel will then
-; move itself again, sigh.)
-;
- mov ecx,[KernelSize]
- mov esi,100000h
- mov edi,10000h
- call bcopy
+setup_move:
+ mov di,trackbuf
+ xor cx,cx ; Number of descriptors
-;
-; Now everything is where it needs to be...
-;
-; When we get here, es points to the final segment, either
-; 9000h or real_mode_seg
-;
-in_proper_place:
-
-;
-; If the default root device is set to FLOPPY (0000h), change to
-; /dev/fd0 (0200h)
-;
- cmp word [es:bs_rootdev],byte 0
- jne root_not_floppy
- mov word [es:bs_rootdev],0200h
-root_not_floppy:
+ mov bx,es ; real_mode_seg
+ mov fs,bx
+ push ds ; We need DS == ES == CS here
+ pop es
-;
-; Copy the disk table to high memory, then re-initialize the floppy
-; controller
-;
-%if IS_SYSLINUX || IS_MDSLINUX
- lgs si,[cs:fdctab]
- mov di,[cs:HeapEnd]
- mov cx,6
- gs rep movsw
- mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
- mov [cs:fdctab+2],es
+ test byte [LoadFlags],LOAD_HIGH
+ jnz .loading_high
+
+; Loading low: move real_mode stuff to 90000h, then move the kernel down
+ mov eax,90000h
+ stosd
+ mov eax,real_mode_seg << 4
+ stosd
+ movzx eax,word [CmdLineEnd]
+ stosd
+ inc cx
+
+ mov eax,10000h ; Target address of low kernel
+ stosd
+ mov eax,100000h ; Where currently loaded
+ stosd
+ neg eax
+ add eax,[KernelEnd]
+ stosd
+ inc cx
+
+ mov bx,9000h ; Revised real mode segment
+
+.loading_high:
+
+ cmp word [InitRDPtr],0 ; Did we have an initrd?
+ je .no_initrd
+
+ mov eax,[fs:su_ramdiskat]
+ stosd
+ mov eax,[InitRDStart]
+ stosd
+ mov eax,[fs:su_ramdisklen]
+ stosd
+ inc cx
+
+.no_initrd:
+ push cx ; Length of descriptor list
+ push word trackbuf
+
+%ifdef DEBUG_TRACERS
+ pushad
+ mov si,trackbuf
+.foo:
+ lodsd
+ call writehex8
+ mov al,'.'
+ call writechr
+ lodsd
+ call writehex8
+ mov al,'.'
+ call writechr
+ lodsd
+ call writehex8
+ call crlf
+ loop .foo
+ popad
%endif
- call cleanup_hardware
-;
-; If we're debugging, wait for a keypress so we can read any debug messages
-;
-%ifdef debug
- xor ax,ax
- int 16h
-%endif
+ mov dword [EntryPoint],run_linux_kernel
+ ; BX points to the final real mode segment, and will be loaded
+ ; into DS.
+ jmp replace_bootstrap
+
+
+run_linux_kernel:
;
; Set up segment registers and the Linux real-mode stack
-; Note: es == the real mode segment
+; Note: ds == the real mode segment
;
-
cli
- mov bx,es
- mov ds,bx
- mov fs,bx
- mov gs,bx
- mov ss,bx
+ mov ax,ds
+ mov ss,ax
mov sp,strict word linux_stack
; Point HeapEnd to the immediate of the instruction above
HeapEnd equ $-2 ; Self-modifying code! Fun!
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
;
; We're done... now RUN THAT KERNEL!!!!
; Setup segment == real mode segment + 020h; we need to jump to offset
; zero in the real mode segment.
;
- add bx,020h
- push bx
+ add ax,020h
+ push ax
push word 0h
retf
@@ -505,14 +498,16 @@ old_kernel:
.load:
mov byte [LoadFlags],al ; Always low
mov word [KernelVersion],ax ; Version 0.00
- jmp read_kernel
+ jmp any_kernel
;
; parse_load_initrd
;
-; Parse an initrd= option and load the initrds. Note that we load
-; from the high end of memory first, so we parse this option from
-; left to right.
+; Parse an initrd= option and load the initrds. This sets
+; InitRDStart and InitRDEnd with dword padding between; we then
+; do a global memory shuffle to move it to the end of memory.
+;
+; On entry, EDI points to where to start loading.
;
parse_load_initrd:
push es
@@ -522,47 +517,50 @@ parse_load_initrd:
push cs
pop es ; DS == real_mode_seg, ES == CS
+ mov [cs:InitRDStart],edi
+ mov [cs:InitRDEnd],edi
+
mov si,[cs:InitRDPtr]
-.find_end:
- lodsb
- cmp al,' '
- ja .find_end
- ; Now SI points to one character beyond the
- ; byte that ended this option.
.get_chunk:
- dec si
+ ; DS:SI points to the start of a name
- ; DS:SI points to a termination byte
-
- xor ax,ax
- xchg al,[si] ; Zero-terminate
- push si ; Save ending byte address
- push ax ; Save ending byte
-
-.find_start:
- dec si
- cmp si,[cs:InitRDPtr]
- je .got_start
- cmp byte [si],','
- jne .find_start
+ mov bx,si
+.find_end:
+ lodsb
+ cmp al,','
+ je .got_end
+ cmp al,' '
+ jbe .got_end
+ jmp .find_end
- ; It's a comma byte
- inc si
+.got_end:
+ push ax ; Terminating character
+ push si ; Next filename (if any)
+ mov byte [si-1],0 ; Zero-terminate
+ mov si,bx ; Current filename
-.got_start:
- push si
+ push di
mov di,InitRD ; Target buffer for mangled name
call mangle_name
+ pop di
call loadinitrd
- pop si
+ pop si
pop ax
- pop di
- mov [di],al ; Restore ending byte
+ mov [si-1],al ; Restore ending byte
- cmp si,[cs:InitRDPtr]
- ja .get_chunk
+ cmp al,','
+ je .get_chunk
+
+ ; Compute the initrd target location
+ mov edx,[cs:InitRDEnd]
+ sub edx,[cs:InitRDStart]
+ mov [su_ramdisklen],edx
+ mov eax,[cs:MyHighMemSize]
+ sub eax,edx
+ and ax,0F000h ; Round to a page boundary
+ mov [su_ramdiskat],eax
pop ds
pop es
@@ -572,6 +570,9 @@ parse_load_initrd:
; Load RAM disk into high memory
;
; Input: InitRD - set to the mangled name of the initrd
+; EDI - location to load
+; Output: EDI - location for next initrd
+; InitRDEnd - updated
;
loadinitrd:
push ds
@@ -579,6 +580,7 @@ loadinitrd:
mov ax,cs ; CS == DS == ES
mov ds,ax
mov es,ax
+ push edi
mov si,InitRD
mov di,InitRDCName
call unmangle_name ; Create human-readable name
@@ -586,46 +588,9 @@ loadinitrd:
mov [InitRDCNameLen],di
mov di,InitRD
call searchdir ; Look for it in directory
+ pop edi
jz .notthere
- mov cx,dx
- shl ecx,16
- mov cx,ax ; ECX <- ram disk length
-
- mov ax,real_mode_seg
- mov es,ax
-
- push ecx ; Bytes to load
- mov edx,[MyHighMemSize] ; End of memory
- dec edx
- mov eax,[RamdiskMax] ; Highest address allowed by kernel
- cmp edx,eax
- jna .memsize_ok
- mov edx,eax ; Adjust to fit inside limit
-.memsize_ok:
- inc edx
- and dx,0F000h ; Round down to 4K boundary
- sub edx,ecx ; Subtract size of ramdisk
- and dx,0F000h ; Round down to 4K boundary
- cmp edx,[KernelEnd] ; Are we hitting the kernel image?
- jb no_high_mem
-
- cmp dword [es:su_ramdisklen],0
- je .highest
- ; The total length has to include the padding between
- ; different ramdisk files, so consider "the length" the
- ; total amount we're about to adjust the base pointer.
- mov ecx,[es:su_ramdiskat]
- sub ecx,edx
-.highest:
- add [es:su_ramdisklen],ecx
-
- mov [es:su_ramdiskat],edx ; Load address
- mov edi,edx ; initrd load address
-
- dec edx ; Note: RamdiskMax is addr-1
- mov [RamdiskMax],edx ; Next initrd loaded here
-
push si
mov si,crlfloading_msg ; Write "Loading "
call cwritestr
@@ -635,10 +600,10 @@ loadinitrd:
call cwritestr
pop si
- pop eax ; Bytes to load
- mov dx,0FFFh ; Pad to page
- mov bx,dot_pause ; Print dots...
- call load_high ; Load the file
+ mov dx,3
+ mov bx,dot_pause
+ call load_high
+ mov [InitRDEnd],ebx
pop es
pop ds
@@ -667,7 +632,6 @@ ready_msg db 'ready.', CR, LF, 0
err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
db CR, LF, 0
err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
-err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
boot_image db 'BOOT_IMAGE='
boot_image_len equ $-boot_image
@@ -679,8 +643,11 @@ RamdiskMax resd 1 ; Highest address for ramdisk
KernelSize resd 1 ; Size of kernel in bytes
KernelSects resd 1 ; Size of kernel in sectors
KernelEnd resd 1 ; Ending address of the kernel image
+InitRDStart resd 1 ; Start of initrd (pre-relocation)
+InitRDEnd resd 1 ; End of initrd (pre-relocation)
CmdLineLen resw 1 ; Length of command line including null
-SetupSecs resw 1 ; Number of setup sectors
+CmdLineEnd resw 1 ; End of the command line in real_mode_seg
+SetupSecs resw 1 ; Number of setup sectors (+bootsect)
InitRDPtr resw 1 ; Pointer to initrd= option in command line
KernelVersion resw 1 ; Kernel protocol version
LoadFlags resb 1 ; Loadflags from kernel
diff --git a/ui.inc b/ui.inc
index 69ba7dc6..06777332 100644
--- a/ui.inc
+++ b/ui.inc
@@ -534,16 +534,21 @@ kernel_good_saved:
; COMBOOT function INT 22h, AX=0016h.
mov si,[Kernel_SI]
mov eax,[Kernel_EAX]
- mov dx,[Kernel_EAX+2]
kernel_good:
- pusha
+ pushad
+
mov si,KernelName
mov di,KernelCName
call unmangle_name
sub di,KernelCName
mov [KernelCNameLen],di
- popa
+
+ ; Default memory limit, can be overridden by image loaders
+ mov eax,[HighMemRsvd]
+ mov [MyHighMemSize],eax
+
+ popad
push di
push ax
@@ -558,7 +563,7 @@ kernel_good:
pop di
;
-; At this point, DX:AX contains the size of the kernel, SI contains
+; At this point, EAX contains the size of the kernel, SI contains
; the file handle/cluster pointer, and ECX contains the extension (if any.)
;
movzx di,byte [KernelType]
diff --git a/version b/version
index be44390d..61867734 100644
--- a/version
+++ b/version
@@ -1 +1 @@
-3.63
+3.70