aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--BUGS4
-rw-r--r--MCONFIG6
-rw-r--r--MCONFIG.build33
-rw-r--r--MCONFIG.embedded21
-rw-r--r--Makefile2
-rw-r--r--TODO22
-rw-r--r--com32/MCONFIG29
-rw-r--r--com32/Makefile2
-rw-r--r--com32/include/dev.h1
-rw-r--r--com32/include/dirent.h18
-rw-r--r--com32/include/netinet/in.h48
-rw-r--r--com32/include/string.h1
-rw-r--r--com32/include/sys/cpu.h21
-rw-r--r--com32/include/sys/dirent.h30
-rw-r--r--com32/include/syslinux/pxe.h487
-rw-r--r--com32/include/syslinux/pxe_api.h566
-rw-r--r--com32/lib/MCONFIG20
-rw-r--r--com32/lib/Makefile3
-rw-r--r--com32/lib/closedir.c16
-rw-r--r--com32/lib/com32.ld68
-rw-r--r--com32/lib/opendir.c19
-rw-r--r--com32/lib/readdir.c42
-rw-r--r--com32/lib/strpcpy.c20
-rw-r--r--com32/lib/sys/entry.S58
-rw-r--r--com32/lib/sys/file.h12
-rw-r--r--com32/lib/sys/open.c6
-rw-r--r--com32/lib/sys/openmem.c60
-rw-r--r--com32/mboot/mboot.c2
-rw-r--r--com32/modules/Makefile3
-rw-r--r--com32/modules/dir.c35
-rw-r--r--com32/modules/host.c42
-rw-r--r--com32/rosh/rosh.c18
-rw-r--r--com32/rosh/rosh.h2
-rw-r--r--com32/tools/.gitignore1
-rw-r--r--com32/tools/Makefile30
-rw-r--r--com32/tools/relocs.c693
-rw-r--r--core/Makefile67
-rw-r--r--core/abort.inc6
-rw-r--r--core/adv.inc22
-rw-r--r--core/bcopy32.inc297
-rw-r--r--core/bcopyxx.inc18
-rw-r--r--core/bios.inc8
-rw-r--r--core/bootsect.inc8
-rw-r--r--core/cache.c134
-rw-r--r--core/cache.inc4
-rw-r--r--core/call16.c27
-rw-r--r--core/callback.inc208
-rwxr-xr-xcore/checksumiso.pl51
-rw-r--r--core/cleanup.inc7
-rw-r--r--core/cmdline.inc4
-rw-r--r--core/com32.inc414
-rw-r--r--core/comboot.inc108
-rw-r--r--core/common.inc25
-rw-r--r--core/config.inc6
-rw-r--r--core/configinit.inc4
-rw-r--r--core/conio.inc15
-rw-r--r--core/cpuinit.inc52
-rw-r--r--core/dir.c47
-rw-r--r--core/diskfs.inc182
-rw-r--r--core/diskio.c312
-rw-r--r--core/diskstart.inc107
-rw-r--r--core/dnsresolv.inc389
-rw-r--r--core/ext2_fs.inc183
-rw-r--r--core/extern.inc26
-rw-r--r--core/extlinux.asm913
-rw-r--r--core/font.inc6
-rw-r--r--core/fs.c284
-rw-r--r--core/fs/btrfs/btrfs.c647
-rw-r--r--core/fs/btrfs/btrfs.h275
-rw-r--r--core/fs/btrfs/crc32c.h50
-rw-r--r--core/fs/ext2/bmap.c185
-rw-r--r--core/fs/ext2/ext2.c495
-rw-r--r--core/fs/ext2/ext2_fs.h305
-rw-r--r--core/fs/fat/fat.c764
-rw-r--r--core/fs/fat/fat_fs.h145
-rw-r--r--core/fs/iso9660/iso9660.c461
-rw-r--r--core/fs/iso9660/iso9660_fs.h27
-rw-r--r--core/fs/lib/mangle.c47
-rw-r--r--core/fs/pxe/dhcp_option.c270
-rw-r--r--core/fs/pxe/dnsresolv.c341
-rw-r--r--core/fs/pxe/idle.c110
-rw-r--r--core/fs/pxe/pxe.c1576
-rw-r--r--core/fs/pxe/pxe.h224
-rw-r--r--core/getc.inc19
-rw-r--r--core/graphics.inc6
-rw-r--r--core/head.inc6
-rw-r--r--core/hello.c30
-rw-r--r--core/highmem.inc6
-rw-r--r--core/idle.inc38
-rw-r--r--core/include/cache.h25
-rw-r--r--core/include/core.h60
-rw-r--r--core/include/disk.h39
-rw-r--r--core/include/fs.h169
-rw-r--r--core/init.inc110
-rw-r--r--core/isolinux.asm584
-rw-r--r--core/kaboom.c16
-rw-r--r--core/layout.inc56
-rw-r--r--core/ldlinux.asm1399
-rw-r--r--core/loadhigh.inc10
-rw-r--r--core/localboot.inc6
-rw-r--r--core/lzo/enter.ash89
-rw-r--r--core/lzo/leave.ash114
-rw-r--r--core/lzo/lzo1c_d.ash184
-rw-r--r--core/lzo/lzo1f_d.ash176
-rw-r--r--core/lzo/lzo1x_d.ash401
-rw-r--r--core/lzo/lzo1x_f1.S63
-rw-r--r--core/lzo/lzo_asm.h287
-rw-r--r--core/macros.inc2
-rw-r--r--core/malloc.c216
-rw-r--r--core/parsecmd.inc9
-rw-r--r--core/parseconfig.inc26
-rw-r--r--core/plaincon.inc2
-rw-r--r--core/pm.inc450
-rw-r--r--core/pmcall.inc70
-rw-r--r--core/prefix.inc17
-rw-r--r--core/printf.c20
-rw-r--r--core/pxeidle.inc122
-rw-r--r--core/pxelinux.asm2493
-rw-r--r--core/rllpack.c105
-rw-r--r--core/rllpack.inc164
-rw-r--r--core/runkernel.inc26
-rw-r--r--core/serirq.inc24
-rw-r--r--core/stack.inc12
-rw-r--r--core/strcpy.inc2
-rw-r--r--core/strecpy.inc2
-rw-r--r--core/syslinux.ld280
-rw-r--r--core/timer.inc46
-rw-r--r--core/ui.inc31
-rw-r--r--core/writedec.inc2
-rw-r--r--core/writehex.inc1
-rw-r--r--core/writestr.inc1
-rw-r--r--doc/comboot.txt19
-rw-r--r--dos/Makefile16
-rw-r--r--dos/argv.c4
-rw-r--r--dos/com16.ld130
-rw-r--r--dos/crt0.S29
-rw-r--r--dos/dosexe.ld131
-rw-r--r--dos/header.S46
-rw-r--r--dos/malloc.c32
-rw-r--r--dos/stdlib.h1
-rw-r--r--dos/syslinux.c72
-rw-r--r--extlinux/btrfs.h22
-rw-r--r--extlinux/main.c403
-rwxr-xr-xlibinstaller/bin2c.pl4
-rw-r--r--libinstaller/setadv.c13
-rw-r--r--libinstaller/syslinux.h16
-rw-r--r--libinstaller/syslxint.h114
-rw-r--r--libinstaller/syslxmod.c302
-rw-r--r--linux/syslinux.c26
-rw-r--r--lzo/.gitignore1
-rw-r--r--lzo/LZO.TXT291
-rw-r--r--lzo/Makefile39
-rw-r--r--lzo/include/lzo/lzo1.h96
-rw-r--r--lzo/include/lzo/lzo1a.h96
-rw-r--r--lzo/include/lzo/lzo1b.h160
-rw-r--r--lzo/include/lzo/lzo1c.h160
-rw-r--r--lzo/include/lzo/lzo1f.h108
-rw-r--r--lzo/include/lzo/lzo1x.h177
-rw-r--r--lzo/include/lzo/lzo1y.h145
-rw-r--r--lzo/include/lzo/lzo1z.h150
-rw-r--r--lzo/include/lzo/lzo2a.h92
-rw-r--r--lzo/include/lzo/lzo_asm.h139
-rw-r--r--lzo/include/lzo/lzoconf.h417
-rw-r--r--lzo/include/lzo/lzodefs.h1807
-rw-r--r--lzo/include/lzo/lzoutil.h73
-rw-r--r--lzo/prepcore.c385
-rw-r--r--lzo/src/compr1b.h81
-rw-r--r--lzo/src/compr1c.h81
-rw-r--r--lzo/src/config1x.h118
-rw-r--r--lzo/src/lzo1_d.ch155
-rw-r--r--lzo/src/lzo1x_1.c50
-rw-r--r--lzo/src/lzo1x_1k.c50
-rw-r--r--lzo/src/lzo1x_1l.c50
-rw-r--r--lzo/src/lzo1x_1o.c50
-rw-r--r--lzo/src/lzo1x_9x.c881
-rw-r--r--lzo/src/lzo1x_c.ch351
-rw-r--r--lzo/src/lzo1x_d.ch466
-rw-r--r--lzo/src/lzo1x_d1.c46
-rw-r--r--lzo/src/lzo1x_d2.c46
-rw-r--r--lzo/src/lzo1x_d3.c108
-rw-r--r--lzo/src/lzo1x_o.c45
-rw-r--r--lzo/src/lzo1x_oo.ch366
-rw-r--r--lzo/src/lzo_conf.h323
-rw-r--r--lzo/src/lzo_crc.c167
-rw-r--r--lzo/src/lzo_dict.h316
-rw-r--r--lzo/src/lzo_dll.ch64
-rw-r--r--lzo/src/lzo_init.c176
-rw-r--r--lzo/src/lzo_mchw.ch242
-rw-r--r--lzo/src/lzo_ptr.c92
-rw-r--r--lzo/src/lzo_ptr.h154
-rw-r--r--lzo/src/lzo_str.c71
-rw-r--r--lzo/src/lzo_swd.ch707
-rw-r--r--lzo/src/lzo_util.c165
-rw-r--r--lzo/src/miniacc.h6553
-rw-r--r--lzo/src/stats1a.h137
-rw-r--r--lzo/src/stats1b.h142
-rw-r--r--lzo/src/stats1c.h61
-rw-r--r--mtools/syslinux.c28
-rw-r--r--version2
-rw-r--r--win32/syslinux.c21
201 files changed, 29963 insertions, 8432 deletions
diff --git a/.gitignore b/.gitignore
index 7657c3d0..c7866759 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,6 +16,7 @@
*.map
*.o
*.orig
+*.raw
*.rej
*.s
*.sec
diff --git a/BUGS b/BUGS
deleted file mode 100644
index 9639da80..00000000
--- a/BUGS
+++ /dev/null
@@ -1,4 +0,0 @@
-Known bugs that have not yet been fixed:
-
-- PXELINUX: Some PXE stacks fail with routing enabled, some with
- routing disabled. Try both?
diff --git a/MCONFIG b/MCONFIG
index a716c6c5..b84e6c56 100644
--- a/MCONFIG
+++ b/MCONFIG
@@ -32,15 +32,17 @@ BOOTDIR = /boot
EXTLINUXDIR = $(BOOTDIR)/extlinux
NASM = nasm
-NASMOPT = -O9999
+NASMOPT = -Ox
PERL = perl
+UPX = upx
CHMOD = chmod
CC = gcc
gcc_ok = $(shell tmpf=gcc_ok.$$$$.tmp; \
- if $(CC) $(1) -c $(topdir)/dummy.c -o $$tmpf 2>/dev/null ; \
+ if $(CC) $(GCCOPT) $(1) -c $(topdir)/dummy.c \
+ -o $$tmpf 2>/dev/null ; \
then echo '$(1)'; else echo '$(2)'; fi; \
rm -f $$tmpf)
diff --git a/MCONFIG.build b/MCONFIG.build
new file mode 100644
index 00000000..d1abff2a
--- /dev/null
+++ b/MCONFIG.build
@@ -0,0 +1,33 @@
+## -*- makefile -*- ------------------------------------------------------
+##
+## Copyright 2001-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.
+##
+## -----------------------------------------------------------------------
+
+##
+## Right now we don't distinguish between "build" system and the "host"
+## system, although we really should...
+##
+include $(topdir)/MCONFIG
+
+OPTFLAGS = -g -Os
+INCLUDES =
+CFLAGS = -W -Wall -Wno-sign-compare -D_FILE_OFFSET_BITS=64 \
+ $(OPTFLAGS) $(INCLUDES)
+LDFLAGS =
+LIBS =
+
+.SUFFIXES: .c .o .S .s .i .elf .com .bin .asm .lst .c32 .lss
+
+%.o: %.c
+ $(CC) $(UMAKEDEPS) $(CFLAGS) -c -o $@ $<
+%.i: %.c
+ $(CC) $(UMAKEDEPS) $(CFLAGS) -E -o $@ $<
+%.s: %.c
+ $(CC) $(UMAKEDEPS) $(CFLAGS) -S -o $@ $<
diff --git a/MCONFIG.embedded b/MCONFIG.embedded
index 586afc3e..bb718963 100644
--- a/MCONFIG.embedded
+++ b/MCONFIG.embedded
@@ -16,14 +16,21 @@
include $(topdir)/MCONFIG
-GCCOPT := $(call gcc_ok,-m32,) \
- $(call gcc_ok,-ffreestanding,) \
- $(call gcc_ok,-fno-stack-protector,) \
- $(call gcc_ok,-falign-functions=0,-malign-functions=0) \
- $(call gcc_ok,-falign-jumps=0,-malign-jumps=0) \
- $(call gcc_ok,-falign-loops=0,-malign-loops=0) \
- -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \
+GCCOPT := $(call gcc_ok,-m32,)
+GCCOPT += $(call gcc_ok,-ffreestanding,)
+GCCOPT += $(call gcc_ok,-fno-stack-protector,)
+GCCOPT += $(call gcc_ok,-fwrapv,)
+GCCOPT += $(call gcc_ok,-freg-struct-return,)
+GCCOPT += -march=i386 -Os -fomit-frame-pointer -mregparm=3 -DREGPARM=3 \
-msoft-float
+GCCOPT += $(call gcc_ok,-fno-exceptions,)
+GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
+GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
+GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
+GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
+GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
+GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
+GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
diff --git a/Makefile b/Makefile
index d0f5e71d..6fbec336 100644
--- a/Makefile
+++ b/Makefile
@@ -52,7 +52,7 @@ BOBJECTS = $(BTARGET) \
# Note: libinstaller is both a BSUBDIR and an ISUBDIR. It contains
# files that depend only on the B phase, but may have to be regenerated
# for "make installer".
-BSUBDIRS = codepage core memdisk modules com32 mbr memdump gpxe sample \
+BSUBDIRS = codepage com32 lzo core memdisk modules mbr memdump gpxe sample \
libinstaller dos win32 dosutil
ITARGET =
IOBJECTS = $(ITARGET) dos/copybs.com \
diff --git a/TODO b/TODO
deleted file mode 100644
index 530b4bfb..00000000
--- a/TODO
+++ /dev/null
@@ -1,22 +0,0 @@
-*** To do in the short term:
-
-- PXELINUX: Figure out localboot/idle problems.
-
-- PXELINUX: Support changing the default server and boot file prefix?
-
-- Library support for all the comboot system calls.
-
-- Deal with non-512-byte sectors (if I can get media which does...)
-
-
-*** Future projects:
-
-- Clean up the command-line parsing.
-
-- Cleaned up documentation, with a real man page.
-
-- API call to get directory listing.
-
-- COM32-based CLI.
-
-- Rewrite the filesystems to run in protected mode C code.
diff --git a/com32/MCONFIG b/com32/MCONFIG
index f8d9d978..3af015e1 100644
--- a/com32/MCONFIG
+++ b/com32/MCONFIG
@@ -1,5 +1,5 @@
## -*- makefile -*- -------------------------------------------------------
-##
+##
## Copyright 2008-2009 H. Peter Anvin - All Rights Reserved
## Copyright 2009 Intel Corporation; author: H. Peter Anvin
##
@@ -17,12 +17,24 @@
include $(topdir)/MCONFIG
-GCCOPT := $(call gcc_ok,-std=gnu99,) \
- $(call gcc_ok,-m32,) \
- $(call gcc_ok,-fno-stack-protector,) \
- -mregparm=3 -DREGPARM=3 -march=i386 -Os
-
-com32 = $(topdir)/com32
+GCCOPT := $(call gcc_ok,-std=gnu99,)
+GCCOPT += $(call gcc_ok,-m32,)
+GCCOPT += $(call gcc_ok,-fno-stack-protector,)
+GCCOPT += $(call gcc_ok,-fwrapv,)
+GCCOPT += $(call gcc_ok,-freg-struct-return,)
+GCCOPT += -mregparm=3 -DREGPARM=3 -march=i386 -Os
+GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+GCCOPT += $(call gcc_ok,-fno-exceptions,)
+GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
+GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
+GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
+GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
+GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
+GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
+GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
+
+com32 := $(topdir)/com32
+RELOCS := $(com32)/tools/relocs
ifneq ($(NOGPL),1)
GPLLIB = $(com32)/gpllib/libcom32gpl.a
@@ -42,7 +54,7 @@ SFLAGS = $(GCCOPT) -W -Wall -march=i386 \
-I$(com32)/libutil/include -I$(com32)/include $(GPLINCLUDE)
COM32LD = $(com32)/lib/com32.ld
-LDFLAGS = -m elf_i386 -T $(COM32LD)
+LDFLAGS = -m elf_i386 --emit-relocs -T $(COM32LD)
LIBGCC := $(shell $(CC) $(GCCOPT) --print-libgcc)
LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g -D_GNU_SOURCE
@@ -81,3 +93,4 @@ C_LNXLIBS = $(com32)/libutil/libutil_lnx.a
%.c32: %.elf
$(OBJCOPY) -O binary $< $@
+ $(RELOCS) $< >> $@ || ( rm -f $@ ; false )
diff --git a/com32/Makefile b/com32/Makefile
index 69a125e6..89d0694e 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,3 +1,3 @@
-SUBDIRS = lib gpllib libutil modules mboot menu samples rosh cmenu hdt gfxboot
+SUBDIRS = tools lib gpllib libutil modules mboot menu samples rosh cmenu hdt gfxboot
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/include/dev.h b/com32/include/dev.h
index 7809fb56..70b3165c 100644
--- a/com32/include/dev.h
+++ b/com32/include/dev.h
@@ -41,6 +41,7 @@ struct input_dev;
struct output_dev;
__extern int opendev(const struct input_dev *, const struct output_dev *, int);
+__extern int openmem(const void *, size_t, int);
/* Common generic devices */
diff --git a/com32/include/dirent.h b/com32/include/dirent.h
index d99b21fb..c4aca4f0 100644
--- a/com32/include/dirent.h
+++ b/com32/include/dirent.h
@@ -10,23 +10,7 @@
#include <stddef.h>
#include <sys/types.h>
-#ifndef NAME_MAX
-#define NAME_MAX 255
-#endif
-
-struct dirent {
- long d_ino; /* Inode/File number */
- off_t d_size; /* Size of file */
- mode_t d_mode; /* Type of file */
- char d_name[NAME_MAX + 1];
-};
-
-typedef struct {
- short dd_stat; /* status return from last lookup */
- uint16_t dd_fd;
- size_t dd_sect;
- char dd_name[NAME_MAX + 1]; /* directory */
-} DIR;
+#include <sys/dirent.h>
__extern DIR *opendir(const char *);
__extern struct dirent *readdir(DIR *);
diff --git a/com32/include/netinet/in.h b/com32/include/netinet/in.h
index 051cc08f..ccf04750 100644
--- a/com32/include/netinet/in.h
+++ b/com32/include/netinet/in.h
@@ -4,37 +4,47 @@
/* COM32 will be running on an i386 platform */
#include <stdint.h>
+#include <klibc/compiler.h>
-static inline uint16_t __htons(uint16_t v)
+#define __htons_macro(v) ((uint16_t) \
+ (((uint16_t)(v) << 8) | \
+ ((uint16_t)(v) >> 8)))
+
+static inline __constfunc uint16_t __htons(uint16_t v)
{
- return ((v) << 8) | ((v) >> 8);
+ return __htons_macro(v);
}
-#define htons(x) __htons(x)
-#define ntohs(x) __htons(x)
+#define htons(x) (__builtin_constant_p(x) ? __htons_macro(x) : __htons(x))
+#define ntohs(x) htons(x)
+
+#define __htonl_macro(v) ((uint32_t) \
+ ((((uint32_t)(v) & 0x000000ff) << 24) | \
+ (((uint32_t)(v) & 0x0000ff00) << 8) | \
+ (((uint32_t)(v) & 0x00ff0000) >> 8) | \
+ (((uint32_t)(v) & 0xff000000) >> 24)))
-static inline uint32_t __htonl(uint32_t v)
+static inline __constfunc uint32_t __htonl(uint32_t v)
{
- if (__builtin_constant_p(v)) {
- return (((v) & 0x000000ff) << 24) |
- (((v) & 0x0000ff00) << 8) |
- (((v) & 0x00ff0000) >> 8) | (((v) & 0xff000000) >> 24);
- } else {
-asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0":"+abcd"(v));
- return v;
- }
+ asm("xchgb %h0,%b0 ; roll $16,%0 ; xchgb %h0,%b0"
+ : "+q" (v));
+ return v;
}
-#define htonl(x) __htonl(x)
-#define ntohl(x) __htonl(x)
+#define htonl(x) (__builtin_constant_p(x) ? __htonl_macro(x) : __htonl(x))
+#define ntohl(x) htonl(x)
+
+#define __htonq_macro(v) ((uint64_t) \
+ (((uint64_t)__htonl_macro((uint32_t)(v)) << 32) | \
+ (__htonl_macro((uint32_t)((uint64_t)(v) >> 32)))))
-static inline uint64_t __htonq(uint64_t v)
+static inline __constfunc uint64_t __htonq(uint64_t v)
{
- return ((uint64_t) __htonl(v) << 32) | __htonl(v >> 32);
+ return ((uint64_t)__htonl(v) << 32) | __htonl(v >> 32);
}
-#define htonq(x) __htonq(x)
-#define ntohq(x) __htonq(x)
+#define htonq(x) (__builtin_constant_p(x) ? __htonq_macro(x) : __htonq(x))
+#define ntohq(x) htonq(x)
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
diff --git a/com32/include/string.h b/com32/include/string.h
index c964ee3b..af9792b6 100644
--- a/com32/include/string.h
+++ b/com32/include/string.h
@@ -23,7 +23,6 @@ __extern char *strcat(char *, const char *);
__extern char *strchr(const char *, int);
__extern int strcmp(const char *, const char *);
__extern char *strcpy(char *, const char *);
-__extern char *strpcpy(char *, const char *);
__extern size_t strcspn(const char *, const char *);
__extern char *strdup(const char *);
__extern char *strndup(const char *, size_t);
diff --git a/com32/include/sys/cpu.h b/com32/include/sys/cpu.h
index dfba02e7..d96ec665 100644
--- a/com32/include/sys/cpu.h
+++ b/com32/include/sys/cpu.h
@@ -23,21 +23,26 @@ static inline void cpuid_count(uint32_t op, uint32_t cnt,
uint32_t * eax, uint32_t * ebx,
uint32_t * ecx, uint32_t * edx)
{
-asm("cpuid":"=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
+asm("pushl %%ebx ; cpuid ; movl %%ebx,%0 ; popl %%ebx":"=a"(*eax), "=SD"(*ebx), "=c"(*ecx),
+ "=d"(*edx)
: "a"(op), "c"(cnt));
}
static inline void cpuid(uint32_t op, uint32_t * eax, uint32_t * ebx,
uint32_t * ecx, uint32_t * edx)
{
- cpuid_count(op, 0, eax, ebx, ecx, edx);
+asm("pushl %%ebx ; cpuid ; movl %%ebx,%0 ; popl %%ebx":"=a"(*eax), "=SD"(*ebx), "=c"(*ecx),
+ "=d"(*edx)
+: "a"(op));
}
static inline __constfunc uint32_t cpuid_eax(uint32_t level)
{
uint32_t v;
-asm("cpuid": "=a"(v): "a"(level):"ebx", "ecx", "edx");
+asm("pushl %%ebx ; cpuid ; popl %%ebx":"=a"(v)
+: "a"(level)
+: "ecx", "edx");
return v;
}
@@ -45,7 +50,9 @@ static inline __constfunc uint32_t cpuid_ebx(uint32_t level)
{
uint32_t v;
-asm("cpuid": "=b"(v), "+a"(level): :"ecx", "edx");
+asm("pushl %%ebx ; cpuid ; movl %%ebx,%0 ; popl %%ebx":"=a"(v)
+: "a"(level)
+: "ecx", "edx");
return v;
}
@@ -53,7 +60,8 @@ static inline __constfunc uint32_t cpuid_ecx(uint32_t level)
{
uint32_t v;
-asm("cpuid": "=c"(v), "+a"(level): :"ebx", "edx");
+asm("pushl %%ebx ; cpuid ; popl %%ebx":"=c"(v), "+a"(level)
+: : "edx");
return v;
}
@@ -61,7 +69,8 @@ static inline __constfunc uint32_t cpuid_edx(uint32_t level)
{
uint32_t v;
-asm("cpuid": "=d"(v), "+a"(level): :"ebx", "ecx");
+asm("pushl %%ebx ; cpuid ; popl %%ebx":"=d"(v), "+a"(level)
+: : "ecx");
return v;
}
diff --git a/com32/include/sys/dirent.h b/com32/include/sys/dirent.h
new file mode 100644
index 00000000..cc2916e1
--- /dev/null
+++ b/com32/include/sys/dirent.h
@@ -0,0 +1,30 @@
+/*
+ * sys/dirent.h
+ */
+
+#ifndef DIRENT_H
+#define DIRENT_H
+
+#include <stdint.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
+struct dirent {
+ uint32_t d_ino;
+ uint32_t d_off;
+ uint16_t d_reclen;
+ uint16_t d_type;
+ char d_name[NAME_MAX + 1];
+};
+
+struct file;
+
+typedef struct {
+ struct file *dd_dir;
+} DIR;
+
+#define DIR_REC_LEN(name) (12 + strlen(name) + 1 + 3) & ~3
+
+#endif /* sys/dirent.h */
diff --git a/com32/include/syslinux/pxe.h b/com32/include/syslinux/pxe.h
index 037642bc..041e0ae1 100644
--- a/com32/include/syslinux/pxe.h
+++ b/com32/include/syslinux/pxe.h
@@ -34,493 +34,10 @@
#ifndef _SYSLINUX_PXE_H
#define _SYSLINUX_PXE_H
-#include <stdint.h>
-#include <netinet/in.h>
-#include <klibc/compiler.h>
-
-/* PXE spec structures and definitions. These mostly follow the PXE
- spec, except when the PXE spec is unnecessarily stupid. Of course,
- that is most of the time. */
-
-/* Basic types; use Unix-like _t convention instead of SCREAMING; also
- re-use types we already have, like in_addr_t. */
-
-typedef uint16_t pxenv_status_t;
-
-#define MAC_ADDR_LEN 16
-typedef uint8_t mac_addr_t[MAC_ADDR_LEN];
-
-/* "Protected mode segment descriptor" according to PXE... */
-typedef struct {
- uint16_t segaddr;
- uint32_t physaddr;
- uint16_t segsize;
-} __packed pxe_segdesc_t;
-
-typedef struct {
- uint16_t offs;
- uint16_t seg;
-} segoff16_t;
-
-typedef struct {
- uint8_t opcode;
-#define BOOTP_REQ 1
-#define BOOTP_REP 2
- uint8_t Hardware;
- uint8_t Hardlen;
- uint8_t Gatehops;
- uint32_t ident;
- uint16_t seconds;
- uint16_t Flags;
-#define BOOTP_BCAST 0x8000
- in_addr_t cip; /* Client IP address */
- in_addr_t yip; /* You IP address */
- in_addr_t sip; /* next server IP address */
- in_addr_t gip; /*relay agent IP address */
- mac_addr_t CAddr;
- uint8_t Sname[64];
- uint8_t bootfile[128];
- union {
-#define BOOTP_DHCPVEND 1024
- uint8_t d[BOOTP_DHCPVEND];
- struct {
- uint8_t magic[4];
-#define VM_RFC1048 0x63825363L
- uint32_t flags;
- uint8_t pad[56];
- } v;
- } vendor;
-} __packed pxe_bootp_t;
-
-/* Function calling structures and constants */
-
-typedef struct s_PXENV_GET_CACHED_INFO {
- pxenv_status_t Status;
- uint16_t PacketType;
-#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
-#define PXENV_PACKET_TYPE_DHCP_ACK 2
-#define PXENV_PACKET_TYPE_CACHED_REPLY 3
- uint16_t BufferSize;
- segoff16_t Buffer;
- uint16_t BufferLimit;
-} __packed t_PXENV_GET_CACHED_INFO;
-
-typedef struct s_PXENV_START_UNDI {
- pxenv_status_t Status;
- uint16_t AX;
- uint16_t BX;
- uint16_t DX;
- uint16_t DI;
- uint16_t ES;
-} __packed t_PXENV_START_UNDI;
-
-typedef struct s_PXENV_STOP_UNDI {
- pxenv_status_t Status;
-} __packed t_PXENV_STOP_UNDI;
-
-typedef struct s_PXENV_START_BASE {
- pxenv_status_t Status;
-} __packed t_PXENV_START_BASE;
-
-typedef struct s_PXENV_STOP_BASE {
- pxenv_status_t Status;
-} __packed t_PXENV_STOP_BASE;
-
-typedef struct s_PXENV_TFTP_OPEN {
- pxenv_status_t Status;
- in_addr_t ServerIPAddress;
- in_addr_t GatewayIPAddress;
- uint8_t FileName[128];
- in_port_t TFTPPort;
- uint16_t PacketSize;
-} __packed t_PXENV_TFTP_OPEN;
-
-typedef struct s_PXENV_TFTP_CLOSE {
- pxenv_status_t Status;
-} __packed t_PXENV_TFTP_CLOSE;
-
-typedef struct s_PXENV_TFTP_READ {
- pxenv_status_t Status;
- uint16_t PacketNumber;
- uint16_t BufferSize;
- segoff16_t Buffer;
-} __packed t_PXENV_TFTP_READ;
-
-typedef struct s_PXENV_TFTP_READ_FILE {
- pxenv_status_t Status;
- uint8_t FileName[128];
- uint32_t BufferSize;
- void *Buffer;
- in_addr_t ServerIPAddress;
- in_addr_t GatewayIPAddress;
- in_addr_t McastIPAddress;
- in_port_t TFTPClntPort;
- in_port_t TFTPSrvPort;
- uint16_t TFTPOpenTimeOut;
- uint16_t TFTPReopenDelay;
-} __packed t_PXENV_TFTP_READ_FILE;
-
-typedef struct s_PXENV_TFTP_GET_FSIZE {
- pxenv_status_t Status;
- in_addr_t ServerIPAddress;
- in_addr_t GatewayIPAddress;
- uint8_t FileName[128];
- uint32_t FileSize;
-} __packed t_PXENV_TFTP_GET_FSIZE;
-
-typedef struct s_PXENV_UDP_OPEN {
- pxenv_status_t status;
- in_addr_t src_ip;
-} __packed t_PXENV_UDP_OPEN;
-
-typedef struct s_PXENV_UDP_CLOSE {
- pxenv_status_t status;
-} __packed t_PXENV_UDP_CLOSE;
-
-typedef struct s_PXENV_UDP_WRITE {
- pxenv_status_t status;
- in_addr_t ip;
- in_addr_t gw;
- in_port_t src_port;
- in_port_t dst_port;
- uint16_t buffer_size;
- segoff16_t buffer;
-} __packed t_PXENV_UDP_WRITE;
-
-typedef struct s_PXENV_UDP_READ {
- pxenv_status_t status;
- in_addr_t src_ip;
- in_addr_t dest_ip;
- in_port_t s_port;
- in_port_t d_port;
- uint16_t buffer_size;
- segoff16_t buffer;
-} __packed t_PXENV_UDP_READ;
-
-typedef struct s_PXENV_UNDI_STARTUP {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_STARTUP;
-
-typedef struct s_PXENV_UNDI_CLEANUP {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_CLEANUP;
-
-typedef struct s_PXENV_UNDI_INITIALIZE {
- pxenv_status_t Status;
- void *ProtocolIni;
- uint8_t reserved[8];
-} __packed t_PXENV_UNDI_INITIALIZE;
-
-#define MAXNUM_MCADDR 8
-typedef struct s_PXENV_UNDI_MCAST_ADDRESS {
- uint16_t MCastAddrCount;
- mac_addr_t McastAddr[MAXNUM_MCADDR];
-} __packed t_PXENV_UNDI_MCAST_ADDRESS;
-
-typedef struct s_PXENV_UNDI_RESET {
- pxenv_status_t Status;
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} __packed t_PXENV_UNDI_RESET;
-
-typedef struct s_PXENV_UNDI_SHUTDOWN {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_SHUTDOWN;
-
-typedef struct s_PXENV_UNDI_OPEN {
- pxenv_status_t Status;
- uint16_t OpenFlag;
- uint16_t PktFilter;
-#define FLTR_DIRECTED 0x0001
-#define FLTR_BRDCST 0x0002
-#define FLTR_PRMSCS 0x0004
-#define FLTR_SRC_RTG 0x0008
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} __packed t_PXENV_UNDI_OPEN;
-
-typedef struct s_PXENV_UNDI_CLOSE {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_CLOSE;
-
-typedef struct s_PXENV_UNDI_TRANSMIT {
- pxenv_status_t Status;
- uint8_t Protocol;
-#define P_UNKNOWN 0
-#define P_IP 1
-#define P_ARP 2
-#define P_RARP 3
- uint8_t XmitFlag;
-#define XMT_DESTADDR 0x0000
-#define XMT_BROADCAST 0x0001
- segoff16_t DestAddr;
- segoff16_t TBD;
- uint32_t Reserved[2];
-} __packed t_PXENV_UNDI_TRANSMIT;
-#define MAX_DATA_BLKS 8
-typedef struct s_PXENV_UNDI_TBD {
- uint16_t ImmedLength;
- segoff16_t Xmit;
- uint16_t DataBlkCount;
- struct DataBlk {
- uint8_t TDPtrType;
- uint8_t TDRsvdByte;
- uint16_t TDDataLen;
- segoff16_t TDDataPtr;
- } DataBlock[MAX_DATA_BLKS];
-} __packed t_PXENV_UNDI_TBD;
-
-typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS {
- pxenv_status_t Status;
- t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
-} __packed t_PXENV_UNDI_SET_MCAST_ADDR;
-
-typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS {
- pxenv_status_t Status;
- mac_addr_t StationAddress;
-} __packed t_PXENV_UNDI_SET_STATION_ADDR;
-
-typedef struct s_PXENV_UNDI_SET_PACKET_FILTER {
- pxenv_status_t Status;
- uint8_t filter;
-} __packed t_PXENV_UNDI_SET_PACKET_FILTER;
-
-typedef struct s_PXENV_UNDI_GET_INFORMATION {
- pxenv_status_t Status;
- uint16_t BaseIo;
- uint16_t IntNumber;
- uint16_t MaxTranUnit;
- uint16_t HwType;
-#define ETHER_TYPE 1
-#define EXP_ETHER_TYPE 2
-#define IEEE_TYPE 6
-#define ARCNET_TYPE 7
- uint16_t HwAddrLen;
- mac_addr_t CurrentNodeAddress;
- mac_addr_t PermNodeAddress;
- uint16_t ROMAddress;
- uint16_t RxBufCt;
- uint16_t TxBufCt;
-} __packed t_PXENV_UNDI_GET_INFORMATION;
-
-typedef struct s_PXENV_UNDI_GET_STATISTICS {
- pxenv_status_t Status;
- uint32_t XmtGoodFrames;
- uint32_t RcvGoodFrames;
- uint32_t RcvCRCErrors;
- uint32_t RcvResourceErrors;
-} __packed t_PXENV_UNDI_GET_STATISTICS;
-
-typedef struct s_PXENV_UNDI_CLEAR_STATISTICS {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_CLEAR_STATISTICS;
-
-typedef struct s_PXENV_UNDI_INITIATE_DIAGS {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_INITIATE_DIAGS;
-
-typedef struct s_PXENV_UNDI_FORCE_INTERRUPT {
- pxenv_status_t Status;
-} __packed t_PXENV_UNDI_FORCE_INTERRUPT;
-
-typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS {
- pxenv_status_t Status;
- in_addr_t InetAddr;
- mac_addr_t MediaAddr;
-} __packed t_PXENV_UNDI_GET_MCAST_ADDR;
-
-typedef struct s_PXENV_UNDI_GET_NIC_TYPE {
- pxenv_status_t Status;
- uint8_t NicType;
-#define PCI_NIC 2
-#define PnP_NIC 3
-#define CardBus_NIC 4
- union {
- struct {
- uint16_t Vendor_ID;
- uint16_t Dev_ID;
- uint8_t Base_Class;
- uint8_t Sub_Class;
- uint8_t Prog_Intf;
- uint8_t Rev;
- uint16_t BusDevFunc;
- uint16_t SubVendor_ID;
- uint16_t SubDevice_ID;
- } pci, cardbus;
- struct {
- uint32_t EISA_Dev_ID;
- uint8_t Base_Class;
- uint8_t Sub_Class;
- uint8_t Prog_Intf;
- uint16_t CardSelNum;
- } __packed pnp;
- } __packed info;
-} __packed t_PXENV_UNDI_GET_NIC_TYPE;
-
-typedef struct s_PXENV_UNDI_GET_IFACE_INFO {
- pxenv_status_t Status;
- uint8_t IfaceType[16];
- uint32_t LinkSpeed;
- uint32_t ServiceFlags;
- uint32_t Reserved[4];
-} __packed t_PXENV_UNDI_GET_NDIS_INFO;
-
-typedef struct s_PXENV_UNDI_GET_STATE {
-#define PXE_UNDI_GET_STATE_STARTED 1
-#define PXE_UNDI_GET_STATE_INITIALIZED 2
-#define PXE_UNDI_GET_STATE_OPENED 3
- pxenv_status_t Status;
- uint8_t UNDIstate;
-} __packed t_PXENV_UNDI_GET_STATE;
-
-typedef struct s_PXENV_UNDI_ISR {
- pxenv_status_t Status;
- uint16_t FuncFlag;
- uint16_t BufferLength;
- uint16_t FrameLength;
- uint16_t FrameHeaderLength;
- segoff16_t Frame;
- uint8_t ProtType;
- uint8_t PktType;
-} __packed t_PXENV_UNDI_ISR;
-#define PXENV_UNDI_ISR_IN_START 1
-#define PXENV_UNDI_ISR_IN_PROCESS 2
-#define PXENV_UNDI_ISR_IN_GET_NEXT 3
-/* One of these will be returned for
- PXENV_UNDI_ISR_IN_START */
-#define PXENV_UNDI_ISR_OUT_OURS 0
-#define PXENV_UNDI_USR_OUT_NOT_OURS 1
-/* One of these will be returned for
- PXENV_UNDI_ISR_IN_PROCESS and
- PXENV_UNDI_ISR_IN_GET_NEXT */
-#define PXENV_UNDI_ISR_OUT_DONE 0
-#define PXENV_UNDI_ISR_OUT_TRANSMIT 2
-#define PXENV_UNDI_ISR_OUT_RECEIVE 3
-#define PXENV_UNDI_ISR_OUT_BUSY 4
-
-/* Function numbers and error codes */
-
-#define PXENV_TFTP_OPEN 0x0020
-#define PXENV_TFTP_CLOSE 0x0021
-#define PXENV_TFTP_READ 0x0022
-#define PXENV_TFTP_READ_FILE 0x0023
-#define PXENV_TFTP_READ_FILE_PMODE 0x0024
-#define PXENV_TFTP_GET_FSIZE 0x0025
-
-#define PXENV_UDP_OPEN 0x0030
-#define PXENV_UDP_CLOSE 0x0031
-#define PXENV_UDP_READ 0x0032
-#define PXENV_UDP_WRITE 0x0033
-
-#define PXENV_START_UNDI 0x0000
-#define PXENV_UNDI_STARTUP 0x0001
-#define PXENV_UNDI_CLEANUP 0x0002
-#define PXENV_UNDI_INITIALIZE 0x0003
-#define PXENV_UNDI_RESET_NIC 0x0004
-#define PXENV_UNDI_SHUTDOWN 0x0005
-#define PXENV_UNDI_OPEN 0x0006
-#define PXENV_UNDI_CLOSE 0x0007
-#define PXENV_UNDI_TRANSMIT 0x0008
-#define PXENV_UNDI_SET_MCAST_ADDR 0x0009
-#define PXENV_UNDI_SET_STATION_ADDR 0x000A
-#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
-#define PXENV_UNDI_GET_INFORMATION 0x000C
-#define PXENV_UNDI_GET_STATISTICS 0x000D
-#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
-#define PXENV_UNDI_INITIATE_DIAGS 0x000F
-#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
-#define PXENV_UNDI_GET_MCAST_ADDR 0x0011
-#define PXENV_UNDI_GET_NIC_TYPE 0x0012
-#define PXENV_UNDI_GET_IFACE_INFO 0x0013
-#define PXENV_UNDI_ISR 0x0014
-#define PXENV_STOP_UNDI 0x0015 /* Overlap...? */
-#define PXENV_UNDI_GET_STATE 0x0015 /* Overlap...? */
-
-#define PXENV_UNLOAD_STACK 0x0070
-#define PXENV_GET_CACHED_INFO 0x0071
-#define PXENV_RESTART_DHCP 0x0072
-#define PXENV_RESTART_TFTP 0x0073
-#define PXENV_MODE_SWITCH 0x0074
-#define PXENV_START_BASE 0x0075
-#define PXENV_STOP_BASE 0x0076
-
-#define PXENV_EXIT_SUCCESS 0x0000
-#define PXENV_EXIT_FAILURE 0x0001
-
-#define PXENV_STATUS_SUCCESS 0x00
-#define PXENV_STATUS_FAILURE 0x01
-#define PXENV_STATUS_BAD_FUNC 0x02
-#define PXENV_STATUS_UNSUPPORTED 0x03
-#define PXENV_STATUS_KEEP_UNDI 0x04
-#define PXENV_STATUS_KEEP_ALL 0x05
-#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
-#define PXENV_STATUS_ARP_TIMEOUT 0x11
-#define PXENV_STATUS_UDP_CLOSED 0x18
-#define PXENV_STATUS_UDP_OPEN 0x19
-#define PXENV_STATUS_TFTP_CLOSED 0x1A
-#define PXENV_STATUS_TFTP_OPEN 0x1B
-#define PXENV_STATUS_MCOPY_PROBLEM 0x20
-#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
-#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
-#define PXENV_STATUS_BIS_INIT_FAILURE 0x23
-#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
-#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
-#define PXENV_STATUS_BIS_FREE_FAILURE 0x26
-#define PXENV_STATUS_BIS_GSI_FAILURE 0x27
-#define PXENV_STATUS_BIS_BAD_CKSUM 0x28
-#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
-#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
-
-#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
-#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
-#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
-#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
-#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
-#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3A
-#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3B
-#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3C
-#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3D
-#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3E
-#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3F
-#define PXENV_STATUS_DHCP_TIMEOUT 0x51
-#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
-#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
-#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
-#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
-#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
-#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
-#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
-#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
-#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
-#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
-#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
-#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
-#define PXENV_STATUS_UNDI_INVALID_STATE 0x6A
-#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B
-#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C
-#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
-#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
-#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
-#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
-#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
-#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xA0
-#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xA1
-#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xA2
-#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xA3
-#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xB0
-#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xC0
-#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xC1
-#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xC2
-#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xC3
-#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xC4
-#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xC5
-#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xC6
-#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xC8
-#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xC9
-#define PXENV_STATUS_LOADER_UNDI_START 0xCA
-#define PXENV_STATUS_LOADER_BC_START 0xCB
+#include <syslinux/pxe_api.h>
/* SYSLINUX-defined PXE utility functions */
-int pxe_get_cached_info(int level, void **buf, size_t * len);
+int pxe_get_cached_info(int level, void **buf, size_t *len);
int pxe_get_nic_type(t_PXENV_UNDI_GET_NIC_TYPE * gnt);
#endif /* _SYSLINUX_PXE_H */
diff --git a/com32/include/syslinux/pxe_api.h b/com32/include/syslinux/pxe_api.h
new file mode 100644
index 00000000..fcc4f873
--- /dev/null
+++ b/com32/include/syslinux/pxe_api.h
@@ -0,0 +1,566 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2007-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * syslinux/pxe_api.h
+ *
+ * PXE type and constant definitions for SYSLINUX
+ */
+
+#ifndef _SYSLINUX_PXE_API_H
+#define _SYSLINUX_PXE_API_H
+
+#include <stdint.h>
+#include <netinet/in.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+/* PXE spec structures and definitions. These mostly follow the PXE
+ spec, except when the PXE spec is unnecessarily stupid. Of course,
+ that is most of the time. */
+
+/* Basic types; use Unix-like _t convention instead of SCREAMING; also
+ re-use types we already have, like in_addr_t. */
+
+typedef uint16_t pxenv_status_t;
+
+#define MAC_ADDR_LEN 16
+typedef uint8_t mac_addr_t[MAC_ADDR_LEN];
+
+/* "Protected mode segment descriptor" according to PXE... */
+typedef struct {
+ uint16_t sel;
+ uint32_t base;
+ uint16_t size;
+} __packed pxe_segdesc_t;
+
+typedef far_ptr_t segoff16_t;
+
+typedef struct {
+ uint8_t opcode;
+#define BOOTP_REQ 1
+#define BOOTP_REP 2
+ uint8_t Hardware;
+ uint8_t Hardlen;
+ uint8_t Gatehops;
+ uint32_t ident;
+ uint16_t seconds;
+ uint16_t Flags;
+#define BOOTP_BCAST 0x8000
+ in_addr_t cip; /* Client IP address */
+ in_addr_t yip; /* You IP address */
+ in_addr_t sip; /* next server IP address */
+ in_addr_t gip; /*relay agent IP address */
+ mac_addr_t CAddr;
+ uint8_t Sname[64];
+ uint8_t bootfile[128];
+ union {
+#define BOOTP_DHCPVEND 1024
+ uint8_t d[BOOTP_DHCPVEND];
+ struct {
+ uint8_t magic[4];
+#define VM_RFC1048 0x63825363L
+ uint32_t flags;
+ uint8_t pad[56];
+ } v;
+ } vendor;
+} __packed pxe_bootp_t;
+
+/* Function calling structures and constants */
+
+typedef struct s_PXENV_GET_CACHED_INFO {
+ pxenv_status_t Status;
+ uint16_t PacketType;
+#define PXENV_PACKET_TYPE_DHCP_DISCOVER 1
+#define PXENV_PACKET_TYPE_DHCP_ACK 2
+#define PXENV_PACKET_TYPE_CACHED_REPLY 3
+ uint16_t BufferSize;
+ segoff16_t Buffer;
+ uint16_t BufferLimit;
+} __packed t_PXENV_GET_CACHED_INFO;
+
+typedef struct s_PXENV_START_UNDI {
+ pxenv_status_t Status;
+ uint16_t AX;
+ uint16_t BX;
+ uint16_t DX;
+ uint16_t DI;
+ uint16_t ES;
+} __packed t_PXENV_START_UNDI;
+
+typedef struct s_PXENV_STOP_UNDI {
+ pxenv_status_t Status;
+} __packed t_PXENV_STOP_UNDI;
+
+typedef struct s_PXENV_START_BASE {
+ pxenv_status_t Status;
+} __packed t_PXENV_START_BASE;
+
+typedef struct s_PXENV_STOP_BASE {
+ pxenv_status_t Status;
+} __packed t_PXENV_STOP_BASE;
+
+typedef struct s_PXENV_TFTP_OPEN {
+ pxenv_status_t Status;
+ in_addr_t ServerIPAddress;
+ in_addr_t GatewayIPAddress;
+ uint8_t FileName[128];
+ in_port_t TFTPPort;
+ uint16_t PacketSize;
+} __packed t_PXENV_TFTP_OPEN;
+
+typedef struct s_PXENV_TFTP_CLOSE {
+ pxenv_status_t Status;
+} __packed t_PXENV_TFTP_CLOSE;
+
+typedef struct s_PXENV_TFTP_READ {
+ pxenv_status_t Status;
+ uint16_t PacketNumber;
+ uint16_t BufferSize;
+ segoff16_t Buffer;
+} __packed t_PXENV_TFTP_READ;
+
+typedef struct s_PXENV_TFTP_READ_FILE {
+ pxenv_status_t Status;
+ uint8_t FileName[128];
+ uint32_t BufferSize;
+ void *Buffer;
+ in_addr_t ServerIPAddress;
+ in_addr_t GatewayIPAddress;
+ in_addr_t McastIPAddress;
+ in_port_t TFTPClntPort;
+ in_port_t TFTPSrvPort;
+ uint16_t TFTPOpenTimeOut;
+ uint16_t TFTPReopenDelay;
+} __packed t_PXENV_TFTP_READ_FILE;
+
+typedef struct s_PXENV_TFTP_GET_FSIZE {
+ pxenv_status_t Status;
+ in_addr_t ServerIPAddress;
+ in_addr_t GatewayIPAddress;
+ uint8_t FileName[128];
+ uint32_t FileSize;
+} __packed t_PXENV_TFTP_GET_FSIZE;
+
+typedef struct s_PXENV_UDP_OPEN {
+ pxenv_status_t status;
+ in_addr_t src_ip;
+} __packed t_PXENV_UDP_OPEN;
+
+typedef struct s_PXENV_UDP_CLOSE {
+ pxenv_status_t status;
+} __packed t_PXENV_UDP_CLOSE;
+
+typedef struct s_PXENV_UDP_WRITE {
+ pxenv_status_t status;
+ in_addr_t ip;
+ in_addr_t gw;
+ in_port_t src_port;
+ in_port_t dst_port;
+ uint16_t buffer_size;
+ segoff16_t buffer;
+} __packed t_PXENV_UDP_WRITE;
+
+typedef struct s_PXENV_UDP_READ {
+ pxenv_status_t status;
+ in_addr_t src_ip;
+ in_addr_t dest_ip;
+ in_port_t s_port;
+ in_port_t d_port;
+ uint16_t buffer_size;
+ segoff16_t buffer;
+} __packed t_PXENV_UDP_READ;
+
+typedef struct s_PXENV_UNDI_STARTUP {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_STARTUP;
+
+typedef struct s_PXENV_UNDI_CLEANUP {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_CLEANUP;
+
+typedef struct s_PXENV_UNDI_INITIALIZE {
+ pxenv_status_t Status;
+ void *ProtocolIni;
+ uint8_t reserved[8];
+} __packed t_PXENV_UNDI_INITIALIZE;
+
+#define MAXNUM_MCADDR 8
+typedef struct s_PXENV_UNDI_MCAST_ADDRESS {
+ uint16_t MCastAddrCount;
+ mac_addr_t McastAddr[MAXNUM_MCADDR];
+} __packed t_PXENV_UNDI_MCAST_ADDRESS;
+
+typedef struct s_PXENV_UNDI_RESET {
+ pxenv_status_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __packed t_PXENV_UNDI_RESET;
+
+typedef struct s_PXENV_UNDI_SHUTDOWN {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_SHUTDOWN;
+
+typedef struct s_PXENV_UNDI_OPEN {
+ pxenv_status_t Status;
+ uint16_t OpenFlag;
+ uint16_t PktFilter;
+#define FLTR_DIRECTED 0x0001
+#define FLTR_BRDCST 0x0002
+#define FLTR_PRMSCS 0x0004
+#define FLTR_SRC_RTG 0x0008
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __packed t_PXENV_UNDI_OPEN;
+
+typedef struct s_PXENV_UNDI_CLOSE {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_CLOSE;
+
+typedef struct s_PXENV_UNDI_TRANSMIT {
+ pxenv_status_t Status;
+ uint8_t Protocol;
+#define P_UNKNOWN 0
+#define P_IP 1
+#define P_ARP 2
+#define P_RARP 3
+ uint8_t XmitFlag;
+#define XMT_DESTADDR 0x0000
+#define XMT_BROADCAST 0x0001
+ segoff16_t DestAddr;
+ segoff16_t TBD;
+ uint32_t Reserved[2];
+} __packed t_PXENV_UNDI_TRANSMIT;
+#define MAX_DATA_BLKS 8
+typedef struct s_PXENV_UNDI_TBD {
+ uint16_t ImmedLength;
+ segoff16_t Xmit;
+ uint16_t DataBlkCount;
+ struct DataBlk {
+ uint8_t TDPtrType;
+ uint8_t TDRsvdByte;
+ uint16_t TDDataLen;
+ segoff16_t TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+} __packed t_PXENV_UNDI_TBD;
+
+typedef struct s_PXENV_UNDI_SET_MCAST_ADDRESS {
+ pxenv_status_t Status;
+ t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf;
+} __packed t_PXENV_UNDI_SET_MCAST_ADDR;
+
+typedef struct s_PXENV_UNDI_SET_STATION_ADDRESS {
+ pxenv_status_t Status;
+ mac_addr_t StationAddress;
+} __packed t_PXENV_UNDI_SET_STATION_ADDR;
+
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER {
+ pxenv_status_t Status;
+ uint8_t filter;
+} __packed t_PXENV_UNDI_SET_PACKET_FILTER;
+
+typedef struct s_PXENV_UNDI_GET_INFORMATION {
+ pxenv_status_t Status;
+ uint16_t BaseIo;
+ uint16_t IntNumber;
+ uint16_t MaxTranUnit;
+ uint16_t HwType;
+#define ETHER_TYPE 1
+#define EXP_ETHER_TYPE 2
+#define IEEE_TYPE 6
+#define ARCNET_TYPE 7
+ uint16_t HwAddrLen;
+ mac_addr_t CurrentNodeAddress;
+ mac_addr_t PermNodeAddress;
+ uint16_t ROMAddress;
+ uint16_t RxBufCt;
+ uint16_t TxBufCt;
+} __packed t_PXENV_UNDI_GET_INFORMATION;
+
+typedef struct s_PXENV_UNDI_GET_STATISTICS {
+ pxenv_status_t Status;
+ uint32_t XmtGoodFrames;
+ uint32_t RcvGoodFrames;
+ uint32_t RcvCRCErrors;
+ uint32_t RcvResourceErrors;
+} __packed t_PXENV_UNDI_GET_STATISTICS;
+
+typedef struct s_PXENV_UNDI_CLEAR_STATISTICS {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_CLEAR_STATISTICS;
+
+typedef struct s_PXENV_UNDI_INITIATE_DIAGS {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_INITIATE_DIAGS;
+
+typedef struct s_PXENV_UNDI_FORCE_INTERRUPT {
+ pxenv_status_t Status;
+} __packed t_PXENV_UNDI_FORCE_INTERRUPT;
+
+typedef struct s_PXENV_UNDI_GET_MCAST_ADDRESS {
+ pxenv_status_t Status;
+ in_addr_t InetAddr;
+ mac_addr_t MediaAddr;
+} __packed t_PXENV_UNDI_GET_MCAST_ADDR;
+
+typedef struct s_PXENV_UNDI_GET_NIC_TYPE {
+ pxenv_status_t Status;
+ uint8_t NicType;
+#define PCI_NIC 2
+#define PnP_NIC 3
+#define CardBus_NIC 4
+ union {
+ struct {
+ uint16_t Vendor_ID;
+ uint16_t Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint8_t Rev;
+ uint16_t BusDevFunc;
+ uint16_t SubVendor_ID;
+ uint16_t SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ uint32_t EISA_Dev_ID;
+ uint8_t Base_Class;
+ uint8_t Sub_Class;
+ uint8_t Prog_Intf;
+ uint16_t CardSelNum;
+ } __packed pnp;
+ } __packed info;
+} __packed t_PXENV_UNDI_GET_NIC_TYPE;
+
+typedef struct s_PXENV_UNDI_GET_IFACE_INFO {
+ pxenv_status_t Status;
+ uint8_t IfaceType[16];
+ uint32_t LinkSpeed;
+ uint32_t ServiceFlags;
+ uint32_t Reserved[4];
+} __packed t_PXENV_UNDI_GET_NDIS_INFO;
+
+typedef struct s_PXENV_UNDI_GET_STATE {
+#define PXE_UNDI_GET_STATE_STARTED 1
+#define PXE_UNDI_GET_STATE_INITIALIZED 2
+#define PXE_UNDI_GET_STATE_OPENED 3
+ pxenv_status_t Status;
+ uint8_t UNDIstate;
+} __packed t_PXENV_UNDI_GET_STATE;
+
+typedef struct s_PXENV_UNDI_ISR {
+ pxenv_status_t Status;
+ uint16_t FuncFlag;
+ uint16_t BufferLength;
+ uint16_t FrameLength;
+ uint16_t FrameHeaderLength;
+ segoff16_t Frame;
+ uint8_t ProtType;
+ uint8_t PktType;
+} __packed t_PXENV_UNDI_ISR;
+
+typedef struct s_PXENV_FILE_API_CHECK {
+ pxenv_status_t Status;
+ uint16_t Size;
+ uint32_t Magic;
+ uint32_t Provider;
+ uint32_t APIMask;
+ uint32_t Flags;
+} __packed t_PXENV_FILE_API_CHECK;
+
+typedef struct s_PXENV_FILE_READ {
+ pxenv_status_t Status;
+ uint16_t FileHandle;
+ uint16_t BufferSize;
+ segoff16_t Buffer;
+} __packed t_PXENV_FILE_READ;
+
+typedef struct s_PXENV_FILE_OPEN {
+ pxenv_status_t Status;
+ uint16_t FileHandle;
+ segoff16_t FileName;
+ uint32_t Reserved;
+} __packed t_PXENV_FILE_OPEN;
+
+typedef struct s_PXENV_GET_FILE_SIZE {
+ pxenv_status_t Status;
+ uint16_t FileHandle;
+ uint32_t FileSize;
+} __packed t_PXENV_GET_FILE_SIZE;
+
+typedef struct s_PXENV_UNLOAD_STACK {
+ pxenv_status_t Status;
+ uint8_t reserved[10];
+} __packed t_PXENV_UNLOAD_STACK;
+
+#define PXENV_UNDI_ISR_IN_START 1
+#define PXENV_UNDI_ISR_IN_PROCESS 2
+#define PXENV_UNDI_ISR_IN_GET_NEXT 3
+/* One of these will be returned for
+ PXENV_UNDI_ISR_IN_START */
+#define PXENV_UNDI_ISR_OUT_OURS 0
+#define PXENV_UNDI_USR_OUT_NOT_OURS 1
+/* One of these will be returned for
+ PXENV_UNDI_ISR_IN_PROCESS and
+ PXENV_UNDI_ISR_IN_GET_NEXT */
+#define PXENV_UNDI_ISR_OUT_DONE 0
+#define PXENV_UNDI_ISR_OUT_TRANSMIT 2
+#define PXENV_UNDI_ISR_OUT_RECEIVE 3
+#define PXENV_UNDI_ISR_OUT_BUSY 4
+
+/* Function numbers and error codes */
+
+#define PXENV_TFTP_OPEN 0x0020
+#define PXENV_TFTP_CLOSE 0x0021
+#define PXENV_TFTP_READ 0x0022
+#define PXENV_TFTP_READ_FILE 0x0023
+#define PXENV_TFTP_READ_FILE_PMODE 0x0024
+#define PXENV_TFTP_GET_FSIZE 0x0025
+
+#define PXENV_UDP_OPEN 0x0030
+#define PXENV_UDP_CLOSE 0x0031
+#define PXENV_UDP_READ 0x0032
+#define PXENV_UDP_WRITE 0x0033
+
+#define PXENV_START_UNDI 0x0000
+#define PXENV_UNDI_STARTUP 0x0001
+#define PXENV_UNDI_CLEANUP 0x0002
+#define PXENV_UNDI_INITIALIZE 0x0003
+#define PXENV_UNDI_RESET_NIC 0x0004
+#define PXENV_UNDI_SHUTDOWN 0x0005
+#define PXENV_UNDI_OPEN 0x0006
+#define PXENV_UNDI_CLOSE 0x0007
+#define PXENV_UNDI_TRANSMIT 0x0008
+#define PXENV_UNDI_SET_MCAST_ADDR 0x0009
+#define PXENV_UNDI_SET_STATION_ADDR 0x000A
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+#define PXENV_UNDI_GET_INFORMATION 0x000C
+#define PXENV_UNDI_GET_STATISTICS 0x000D
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+#define PXENV_UNDI_INITIATE_DIAGS 0x000F
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+#define PXENV_UNDI_GET_MCAST_ADDR 0x0011
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define PXENV_UNDI_GET_IFACE_INFO 0x0013
+#define PXENV_UNDI_ISR 0x0014
+#define PXENV_STOP_UNDI 0x0015 /* Overlap...? */
+#define PXENV_UNDI_GET_STATE 0x0015 /* Overlap...? */
+
+#define PXENV_UNLOAD_STACK 0x0070
+#define PXENV_GET_CACHED_INFO 0x0071
+#define PXENV_RESTART_DHCP 0x0072
+#define PXENV_RESTART_TFTP 0x0073
+#define PXENV_MODE_SWITCH 0x0074
+#define PXENV_START_BASE 0x0075
+#define PXENV_STOP_BASE 0x0076
+
+/* gPXE extensions... */
+#define PXENV_FILE_OPEN 0x00e0
+#define PXENV_FILE_CLOSE 0x00e1
+#define PXENV_FILE_SELECT 0x00e2
+#define PXENV_FILE_READ 0x00e3
+#define PXENV_GET_FILE_SIZE 0x00e4
+#define PXENV_FILE_EXEC 0x00e5
+#define PXENV_FILE_API_CHECK 0x00e6
+
+/* Exit codes */
+#define PXENV_EXIT_SUCCESS 0x0000
+#define PXENV_EXIT_FAILURE 0x0001
+
+/* Status codes */
+#define PXENV_STATUS_SUCCESS 0x00
+#define PXENV_STATUS_FAILURE 0x01
+#define PXENV_STATUS_BAD_FUNC 0x02
+#define PXENV_STATUS_UNSUPPORTED 0x03
+#define PXENV_STATUS_KEEP_UNDI 0x04
+#define PXENV_STATUS_KEEP_ALL 0x05
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+#define PXENV_STATUS_ARP_TIMEOUT 0x11
+#define PXENV_STATUS_UDP_CLOSED 0x18
+#define PXENV_STATUS_UDP_OPEN 0x19
+#define PXENV_STATUS_TFTP_CLOSED 0x1a
+#define PXENV_STATUS_TFTP_OPEN 0x1b
+#define PXENV_STATUS_MCOPY_PROBLEM 0x20
+#define PXENV_STATUS_BIS_INTEGRITY_FAILURE 0x21
+#define PXENV_STATUS_BIS_VALIDATE_FAILURE 0x22
+#define PXENV_STATUS_BIS_INIT_FAILURE 0x23
+#define PXENV_STATUS_BIS_SHUTDOWN_FAILURE 0x24
+#define PXENV_STATUS_BIS_GBOA_FAILURE 0x25
+#define PXENV_STATUS_BIS_FREE_FAILURE 0x26
+#define PXENV_STATUS_BIS_GSI_FAILURE 0x27
+#define PXENV_STATUS_BIS_BAD_CKSUM 0x28
+#define PXENV_STATUS_TFTP_CANNOT_ARP_ADDRESS 0x30
+#define PXENV_STATUS_TFTP_OPEN_TIMEOUT 0x32
+
+#define PXENV_STATUS_TFTP_UNKNOWN_OPCODE 0x33
+#define PXENV_STATUS_TFTP_READ_TIMEOUT 0x35
+#define PXENV_STATUS_TFTP_ERROR_OPCODE 0x36
+#define PXENV_STATUS_TFTP_CANNOT_OPEN_CONNECTION 0x38
+#define PXENV_STATUS_TFTP_CANNOT_READ_FROM_CONNECTION 0x39
+#define PXENV_STATUS_TFTP_TOO_MANY_PACKAGES 0x3a
+#define PXENV_STATUS_TFTP_FILE_NOT_FOUND 0x3b
+#define PXENV_STATUS_TFTP_ACCESS_VIOLATION 0x3c
+#define PXENV_STATUS_TFTP_NO_MCAST_ADDRESS 0x3d
+#define PXENV_STATUS_TFTP_NO_FILESIZE 0x3e
+#define PXENV_STATUS_TFTP_INVALID_PACKET_SIZE 0x3f
+#define PXENV_STATUS_DHCP_TIMEOUT 0x51
+#define PXENV_STATUS_DHCP_NO_IP_ADDRESS 0x52
+#define PXENV_STATUS_DHCP_NO_BOOTFILE_NAME 0x53
+#define PXENV_STATUS_DHCP_BAD_IP_ADDRESS 0x54
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDRESS 0x67
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CHECKSUM 0x68
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define PXENV_STATUS_UNDI_INVALID_STATE 0x6a
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6b
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6c
+#define PXENV_STATUS_BSTRAP_PROMPT_MENU 0x74
+#define PXENV_STATUS_BSTRAP_MCAST_ADDR 0x76
+#define PXENV_STATUS_BSTRAP_MISSING_LIST 0x77
+#define PXENV_STATUS_BSTRAP_NO_RESPONSE 0x78
+#define PXENV_STATUS_BSTRAP_FILE_TOO_BIG 0x79
+#define PXENV_STATUS_BINL_CANCELED_BY_KEYSTROKE 0xa0
+#define PXENV_STATUS_BINL_NO_PXE_SERVER 0xa1
+#define PXENV_STATUS_NOT_AVAILABLE_IN_PMODE 0xa2
+#define PXENV_STATUS_NOT_AVAILABLE_IN_RMODE 0xa3
+#define PXENV_STATUS_BUSD_DEVICE_NOT_SUPPORTED 0xb0
+#define PXENV_STATUS_LOADER_NO_FREE_BASE_MEMORY 0xc0
+#define PXENV_STATUS_LOADER_NO_BC_ROMID 0xc1
+#define PXENV_STATUS_LOADER_BAD_BC_ROMID 0xc2
+#define PXENV_STATUS_LOADER_BAD_BC_RUNTIME_IMAGE 0xc3
+#define PXENV_STATUS_LOADER_NO_UNDI_ROMID 0xc4
+#define PXENV_STATUS_LOADER_BAD_UNDI_ROMID 0xc5
+#define PXENV_STATUS_LOADER_BAD_UNDI_DRIVER_IMAGE 0xc6
+#define PXENV_STATUS_LOADER_NO_PXE_STRUCT 0xc8
+#define PXENV_STATUS_LOADER_NO_PXENV_STRUCT 0xc9
+#define PXENV_STATUS_LOADER_UNDI_START 0xca
+#define PXENV_STATUS_LOADER_BC_START 0xcb
+
+#endif /* _SYSLINUX_PXE_API_H */
diff --git a/com32/lib/MCONFIG b/com32/lib/MCONFIG
index 1eb18db1..7e092df3 100644
--- a/com32/lib/MCONFIG
+++ b/com32/lib/MCONFIG
@@ -2,9 +2,20 @@
include $(topdir)/MCONFIG
-GCCOPT := $(call gcc_ok,-std=gnu99,) \
- $(call gcc_ok,-m32,) \
- $(call gcc_ok,-fno-stack-protector,) \
+GCCOPT := $(call gcc_ok,-std=gnu99,)
+GCCOPT += $(call gcc_ok,-m32,)
+GCCOPT += $(call gcc_ok,-fno-stack-protector,)
+GCCOPT += $(call gcc_ok,-fwrapv,)
+GCCOPT += $(call gcc_ok,-freg-struct-return,)
+GCCOPT += $(call gcc_ok,-fPIE,-fPIC)
+GCCOPT += $(call gcc_ok,-fno-exceptions,)
+GCCOPT += $(call gcc_ok,-fno-asynchronous-unwind-tables,)
+GCCOPT += $(call gcc_ok,-fno-strict-aliasing,)
+GCCOPT += $(call gcc_ok,-falign-functions=0,-malign-functions=0)
+GCCOPT += $(call gcc_ok,-falign-jumps=0,-malign-jumps=0)
+GCCOPT += $(call gcc_ok,-falign-labels=0,-malign-labels=0)
+GCCOPT += $(call gcc_ok,-falign-loops=0,-malign-loops=0)
+GCCOPT += $(call gcc_ok,-mpreferred-stack-boundary=2,)
INCLUDE = -I.
STRIP = strip --strip-all -R .comment -R .note
@@ -22,8 +33,7 @@ LIBFLAGS = -DDYNAMIC_CRC_TABLE -DPNG_NO_CONSOLE_IO \
REQFLAGS = $(GCCOPT) -g -mregparm=3 -DREGPARM=3 -D__COM32__ \
-nostdinc -iwithprefix include -I. -I./sys -I../include
-OPTFLAGS = -Os -march=i386 -falign-functions=0 -falign-jumps=0 \
- -falign-labels=0 -ffast-math -fomit-frame-pointer
+OPTFLAGS = -Os -march=i386 -ffast-math -fomit-frame-pointer
WARNFLAGS = -W -Wall -Wpointer-arith -Wwrite-strings -Wstrict-prototypes -Winline
CFLAGS = $(OPTFLAGS) $(REQFLAGS) $(WARNFLAGS) $(LIBFLAGS)
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index ff5887b0..e66b6560 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -17,7 +17,7 @@ LIBOBJS = \
exit.o onexit.o \
perror.o printf.o puts.o qsort.o realloc.o seed48.o snprintf.o \
sprintf.o srand48.o sscanf.o stack.o strcasecmp.o strcat.o \
- strchr.o strcmp.o strcpy.o strpcpy.o strdup.o strlen.o \
+ strchr.o strcmp.o strcpy.o strdup.o strlen.o \
strerror.o strnlen.o \
strncasecmp.o strncat.o strncmp.o strncpy.o strndup.o \
stpcpy.o stpncpy.o \
@@ -40,6 +40,7 @@ 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/openmem.o \
sys/isatty.o sys/fstat.o \
\
sys/zfile.o sys/zfopen.o \
diff --git a/com32/lib/closedir.c b/com32/lib/closedir.c
index f8bbbabd..b3f55642 100644
--- a/com32/lib/closedir.c
+++ b/com32/lib/closedir.c
@@ -13,17 +13,17 @@
int closedir(DIR * dir)
{
- int rv;
- com32sys_t regs;
- if (dir == NULL) {
- rv = 0;
- } else {
- memset(&regs, 0, sizeof regs); /* ?Needed? */
+ int rv = -1;
+
+ if (dir) {
+ com32sys_t regs;
+ memset(&regs, 0, sizeof regs);
regs.eax.w[0] = 0x0022;
- regs.esi.w[0] = dir->dd_fd;
+ regs.esi.l = (uint32_t)dir;
__com32.cs_intcall(0x22, &regs, &regs);
- free(dir); /* garbage collection? */
+ free(dir);
rv = 0;
}
+
return rv;
}
diff --git a/com32/lib/com32.ld b/com32/lib/com32.ld
index 36d5b6ed..37ee46cf 100644
--- a/com32/lib/com32.ld
+++ b/com32/lib/com32.ld
@@ -11,8 +11,9 @@ ENTRY(_start)
SECTIONS
{
/* Read-only sections, merged into text segment: */
- . = 0x101000;
+ . = 0;
PROVIDE (__executable_start = .);
+ PROVIDE (_stext = .);
.init :
{
@@ -28,40 +29,52 @@ SECTIONS
{
KEEP (*(.fini))
} =0x90909090
- PROVIDE (__etext = .);
PROVIDE (_etext = .);
- PROVIDE (etext = .);
+
+ __rodata_start = .;
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
+ __rodata_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(4);
- PROVIDE (__preinit_array_start = .);
- .preinit_array : { *(.preinit_array) }
- PROVIDE (__preinit_array_end = .);
- PROVIDE (__init_array_start = .);
- .init_array : { *(.init_array) }
- PROVIDE (__init_array_end = .);
- PROVIDE (__fini_array_start = .);
- .fini_array : { *(.fini_array) }
- PROVIDE (__fini_array_end = .);
- PROVIDE (__ctors_start = .);
- .ctors :
- {
+ .preinit_array : {
+ PROVIDE (__preinit_array_start = .);
+ *(.preinit_array)
+ PROVIDE (__preinit_array_end = .);
+ }
+ .init_array : {
+ PROVIDE (__init_array_start = .);
+ *(.init_array)
+ PROVIDE (__init_array_end = .);
+ }
+ .fini_array : {
+ PROVIDE (__fini_array_start = .);
+ *(.fini_array)
+ PROVIDE (__fini_array_end = .);
+ }
+ .ctors : {
+ PROVIDE (__ctors_start = .);
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
+ PROVIDE (__ctors_end = .);
}
- PROVIDE (__ctors_end = .);
- PROVIDE (__dtors_start = .);
- .dtors :
- {
+ .dtors : {
+ PROVIDE (__dtors_start = .);
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
+ PROVIDE (__dtors_end = .);
+ }
+
+ .got : {
+ PROVIDE (__got_start = .);
+ KEEP (*(.got.plt))
+ KEEP (*(.got))
+ PROVIDE (__got_end = .);
}
- PROVIDE (__dtors_end = .);
/* Adjust the address for the data segment. Avoid mixing code and
data within same 128-byte chunk. */
@@ -69,12 +82,14 @@ SECTIONS
.data :
{
- *(.data .data.* .gnu.linkonce.d.*)
+ _sdata = .;
+ KEEP(*(.data .data.* .gnu.linkonce.d.*))
SORT(CONSTRUCTORS)
+ *(.data1)
+ . = ALIGN(4);
+ _edata = .;
}
- .data1 : { *(.data1) }
- _edata = .;
- PROVIDE (edata = .);
+
__bss_start = .;
.bss :
{
@@ -84,11 +99,10 @@ SECTIONS
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections. */
- . = ALIGN(32 / 8);
+ . = ALIGN(4);
}
- . = ALIGN(32 / 8);
+ . = ALIGN(4);
_end = .;
- PROVIDE (end = .);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
diff --git a/com32/lib/opendir.c b/com32/lib/opendir.c
index 6fc0f14f..6f91032b 100644
--- a/com32/lib/opendir.c
+++ b/com32/lib/opendir.c
@@ -13,11 +13,9 @@
DIR *opendir(const char *pathname)
{
- DIR *newdir;
+ DIR *newdir = NULL;
com32sys_t regs;
-
- newdir = NULL;
-
+
strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size);
regs.eax.w[0] = 0x0020;
@@ -25,16 +23,13 @@ DIR *opendir(const char *pathname)
regs.es = SEG(__com32.cs_bounce);
__com32.cs_intcall(0x22, &regs, &regs);
-
+
if (!(regs.eflags.l & EFLAGS_CF)) {
- /* Initialization: malloc() then zero */
- newdir = calloc(1, sizeof(DIR));
- strcpy(newdir->dd_name, pathname);
- newdir->dd_fd = regs.esi.w[0];
- newdir->dd_sect = regs.eax.l;
- newdir->dd_stat = 0;
+ /* Initialization: malloc() then zero */
+ newdir = calloc(1, sizeof(DIR));
+ newdir->dd_dir = (struct file *)regs.eax.l;
}
-
+
/* We're done */
return newdir;
}
diff --git a/com32/lib/readdir.c b/com32/lib/readdir.c
index 2ec7c7b3..07ca3955 100644
--- a/com32/lib/readdir.c
+++ b/com32/lib/readdir.c
@@ -15,40 +15,12 @@ struct dirent *readdir(DIR * dir)
{
struct dirent *newde;
com32sys_t regs;
-
- newde = NULL;
- if ((dir != NULL) && (dir->dd_fd != 0) && (dir->dd_stat >= 0)) {
- memset(__com32.cs_bounce, 0, 32);
- memset(&regs, 0, sizeof(regs));
-
- regs.eax.w[0] = 0x0021;
- regs.esi.w[0] = dir->dd_fd;
- regs.edi.w[0] = OFFS(__com32.cs_bounce);
- regs.es = SEG(__com32.cs_bounce);
-
- __com32.cs_intcall(0x22, &regs, &regs);
-
- /* Don't do this as we won't be able to rewind.
- dir->dd_fd = regs.esi.w[0]; /* Shouldn't be needed? */
- if ((!(regs.eflags.l & EFLAGS_CF)) && (regs.esi.w[0] != 0)) {
- newde = calloc(1, sizeof(newde));
- if (newde != NULL) {
- strcpy(newde->d_name, __com32.cs_bounce);
- newde->d_mode = regs.edx.b[0];
- newde->d_size = regs.eax.l;
- newde->d_ino = regs.ebx.l;
- dir->dd_stat = 1;
- } else {
- dir->dd_stat = -2;
- errno = ENOMEM;
- }
- } else {
- dir->dd_stat = -1;
- errno = EIO; /* Is this the right nmber? */
- }
- } else {
- errno = EBADF;
- }
-
+
+ memset(&regs, 0, sizeof(regs));
+ regs.eax.w[0] = 0x0021;
+ regs.esi.l = (uint32_t)dir;
+ __com32.cs_intcall(0x22, &regs, &regs);
+ newde = (struct dirent *)(regs.eax.l);
+
return newde;
}
diff --git a/com32/lib/strpcpy.c b/com32/lib/strpcpy.c
deleted file mode 100644
index a4fd2a06..00000000
--- a/com32/lib/strpcpy.c
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * strpcpy.c
- *
- * strpcpy() - strcpy() which returns a pointer to the final null
- */
-
-#include <string.h>
-
-char *strpcpy(char *dst, const char *src)
-{
- char *q = dst;
- const char *p = src;
- char ch;
-
- do {
- *q++ = ch = *p++;
- } while (ch);
-
- return q - 1;
-}
diff --git a/com32/lib/sys/entry.S b/com32/lib/sys/entry.S
index 53bf2ecb..a3a1eaa8 100644
--- a/com32/lib/sys/entry.S
+++ b/com32/lib/sys/entry.S
@@ -36,54 +36,78 @@
.globl _start
.type _start, @function
_start:
- /* This first instruction acts as COM32 magic number */
- movl $0x21cd4cff,%eax
+ /* This first instruction acts as COM32R magic number */
+ movl $0x21cd4cfe,%eax
/* Upwards string operations */
cld
+ /* Find our own location */
+ call 1f
+1: popl %ebx
+ addl $_GLOBAL_OFFSET_TABLE_ + (. - 1b), %ebx
+
+ /* Process relocations (which overlay the .bss segment) */
+ leal _edata@GOTOFF(%ebx),%esi
+ leal _start@GOTOFF(%ebx),%edx
+2: lodsl
+ andl %eax,%eax
+ jz 3f
+ addl %edx,(%eax,%edx)
+ jmp 2b
+3:
+ /* Relocate the GOT (is this right?) */
+ leal __got_start@GOTOFF(%ebx),%esi
+ leal __got_end@GOTOFF(%ebx),%edi
+4:
+ addl %edx,(%esi)
+ addl $4,%esi
+ cmpl %edi,%esi
+ jb 4b
+
/* Zero the .bss segment */
xorl %eax,%eax
- movl $__bss_start,%edi # Symbol provided by linker
- movl $_end+3,%ecx # Symbol provided by linker
+ leal __bss_start@GOTOFF(%ebx),%edi
+ leal _end+3@GOTOFF(%ebx),%ecx
subl %edi,%ecx
shrl $2,%ecx
rep ; stosl
/* Copy COM32 invocation parameters */
leal 4(%esp),%esi # Argument list
- movl $__com32,%edi
+ leal __com32@GOTOFF(%ebx),%edi
movl $(COM32_ARGS),%ecx
movl %esp,-4(%edi) # Save the initial stack ptr
cmpl (%esi),%ecx
- jbe 1f
+ jbe 5f
movl (%esi),%ecx
-1: inc %ecx # Copy the argument count, too
+5: inc %ecx # Copy the argument count, too
rep ; movsl
/* Parse the command line (assumes REGPARM) */
- movl __com32+4,%edx # Command line
- pushl %edx # Make space for argv
+ movl __com32+4@GOTOFF(%ebx),%edx # Command line
+ pushl %edx # Make space for argv
movl %esp,%eax
call __parse_argv
- pushl %eax # Save argc
+ pushl %eax # Save argc
/* Look for library initialization functions */
- movl $__ctors_start, %esi
-2:
- cmpl $__ctors_end, %esi
- jae 3f
+ leal __ctors_start@GOTOFF(%ebx),%esi
+ leal __ctors_end@GOTOFF(%ebx),%edi
+6:
+ cmpl %edi,%esi
+ jae 7f
call *(%esi)
addl $4,%esi
- jmp 2b
+ jmp 6b
/*
* Actually run main. This assumes REGPARM is used!!!!
*/
-3:
+7:
popl %eax # argc
popl %edx # argv
call main
- call *(__exit_handler)
+ call *__exit_handler@GOTOFF(%ebx)
hlt
.size _start, .-_start
diff --git a/com32/lib/sys/file.h b/com32/lib/sys/file.h
index fff91b19..66192fbf 100644
--- a/com32/lib/sys/file.h
+++ b/com32/lib/sys/file.h
@@ -56,18 +56,18 @@ struct input_dev {
uint16_t dev_magic; /* Magic number */
uint16_t flags; /* Flags */
int fileflags; /* Permitted file flags */
- ssize_t(*read) (struct file_info *, void *, size_t);
- int (*close) (struct file_info *);
- int (*open) (struct file_info *);
+ ssize_t (*read)(struct file_info *, void *, size_t);
+ int (*close)(struct file_info *);
+ int (*open)(struct file_info *);
};
struct output_dev {
uint16_t dev_magic; /* Magic number */
uint16_t flags; /* Flags */
int fileflags;
- ssize_t(*write) (struct file_info *, const void *, size_t);
- int (*close) (struct file_info *);
- int (*open) (struct file_info *);
+ ssize_t (*write)(struct file_info *, const void *, size_t);
+ int (*close)(struct file_info *);
+ int (*open)(struct file_info *);
const struct output_dev *fallback; /* Fallback option for certain consoles */
};
diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c
index aac5e6f4..0bd490c7 100644
--- a/com32/lib/sys/open.c
+++ b/com32/lib/sys/open.c
@@ -41,7 +41,7 @@
extern ssize_t __file_read(struct file_info *, void *, size_t);
extern int __file_close(struct file_info *);
-static const struct input_dev file_dev = {
+const struct input_dev __file_dev = {
.dev_magic = __DEV_MAGIC,
.flags = __DEV_FILE | __DEV_INPUT,
.fileflags = O_RDONLY,
@@ -56,7 +56,7 @@ int open(const char *pathname, int flags, ...)
int fd;
struct file_info *fp;
- fd = opendev(&file_dev, NULL, flags);
+ fd = opendev(&__file_dev, NULL, flags);
if (fd < 0)
return -1;
@@ -79,7 +79,7 @@ int open(const char *pathname, int flags, ...)
{
uint16_t blklg2;
- asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0]));
+ asm("bsrw %1,%0" : "=r" (blklg2) : "rm" (regs.ecx.w[0]));
fp->i.blocklg2 = blklg2;
}
fp->i.length = regs.eax.l;
diff --git a/com32/lib/sys/openmem.c b/com32/lib/sys/openmem.c
new file mode 100644
index 00000000..13a45c2a
--- /dev/null
+++ b/com32/lib/sys/openmem.c
@@ -0,0 +1,60 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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 <com32.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "file.h"
+
+/*
+ * openmem.c
+ *
+ * Open a chunk of memory as if it was a file
+ */
+
+const struct input_dev __file_dev;
+
+int openmem(const void *base, size_t len, int flags)
+{
+ com32sys_t regs;
+ int fd;
+ struct file_info *fp;
+
+ fd = opendev(&__file_dev, NULL, flags);
+
+ if (fd < 0)
+ return -1;
+
+ fp->i.length = fp->i.nbytes = len;
+ fp->i.datap = (void *)base;
+ fp->i.filedes = 0; /* No actual file */
+ fp->i.offset = 0;
+
+ return fd;
+}
diff --git a/com32/mboot/mboot.c b/com32/mboot/mboot.c
index 8425e068..a0b55628 100644
--- a/com32/mboot/mboot.c
+++ b/com32/mboot/mboot.c
@@ -135,7 +135,7 @@ static int get_modules(char **argv, struct module_data **mdp)
char *p;
mp->cmdline = p = malloc(arglen);
for (; *argp && strcmp(*argp, module_separator); argp++) {
- p = strpcpy(p, *argp);
+ p = stpcpy(p, *argp);
*p++ = ' ';
}
*--p = '\0';
diff --git a/com32/modules/Makefile b/com32/modules/Makefile
index 35906587..b7d6212e 100644
--- a/com32/modules/Makefile
+++ b/com32/modules/Makefile
@@ -21,7 +21,8 @@ include ../MCONFIG
MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \
disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \
meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \
- kbdmap.c32 cmd.c32 vpdtest.c32 gpxecmd.c32 ifcpu.c32
+ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 dir.c32 gpxecmd.c32 \
+ ifcpu.c32
TESTFILES =
diff --git a/com32/modules/dir.c b/com32/modules/dir.c
new file mode 100644
index 00000000..913c2ca7
--- /dev/null
+++ b/com32/modules/dir.c
@@ -0,0 +1,35 @@
+/*
+ * A dir test module
+ */
+#include <stdio.h>
+#include <console.h>
+#include <string.h>
+#include <com32.h>
+#include <dirent.h>
+
+int main(int argc, char *argv[])
+{
+ DIR *dir;
+ struct dirent *de;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ if (argc != 2) {
+ printf("Usage: dir direcotry\n");
+ return 0;
+ }
+
+ dir = opendir(argv[1]);
+ if (dir == NULL) {
+ printf("Unable to read dir: %s\n", argv[1]);
+ return 0;
+ }
+
+ while ((de = readdir(dir)) != NULL)
+ printf("%s\n", de->d_name);
+
+ closedir(dir);
+
+ return 0;
+}
+
diff --git a/com32/modules/host.c b/com32/modules/host.c
new file mode 100644
index 00000000..94ca876d
--- /dev/null
+++ b/com32/modules/host.c
@@ -0,0 +1,42 @@
+#include <stdio.h>
+#include <console.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <com32.h>
+
+static struct in_addr dnsresolve(const char *hostname)
+{
+ com32sys_t regs;
+ struct in_addr addr;
+
+ strcpy(__com32.cs_bounce, hostname);
+
+ regs.eax.w[0] = 0x0010;
+ regs.es = SEG(__com32.cs_bounce);
+ regs.ebx.w[0] = OFFS(__com32.cs_bounce);
+ __intcall(0x22, &regs, &regs);
+
+ addr.s_addr = regs.eax.l;
+ return addr;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ struct in_addr addr;
+
+ openconsole(&dev_null_r, &dev_stdcon_w);
+
+ for (i = 1; i < argc; i++) {
+ addr = dnsresolve(argv[i]);
+
+ printf("%-39s %08X %d.%d.%d.%d\n",
+ argv[i], ntohl(addr.s_addr),
+ ((uint8_t *)&addr.s_addr)[0],
+ ((uint8_t *)&addr.s_addr)[1],
+ ((uint8_t *)&addr.s_addr)[2],
+ ((uint8_t *)&addr.s_addr)[3]);
+ }
+
+ return 0;
+}
diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c
index 9a4edae2..2221bb0a 100644
--- a/com32/rosh/rosh.c
+++ b/com32/rosh/rosh.c
@@ -389,12 +389,12 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
ROSH_DEBUG("--'%s'\n", filestr);
}
fd = open(filestr, O_RDONLY);
- if (fd != -1) {
+ if (fd == -1) {
status = fstat(fd, &fdstat);
- if (S_ISDIR(fdstat.st_mode)) {
+ if (S_ISDIR(fdstat.st_mode)) {
ROSH_DEBUG("PATH '%s' is a directory\n", ifilstr);
d = fdopendir(fd);
- de = readdir(d);
+ de = readdir(d);
while (de != NULL) {
#ifdef DO_DEBUG
filestr2[0] = 0;
@@ -423,19 +423,18 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
}
} else {
#ifdef __COM32__
- if (filestr[strlen(filestr) - 1] == SEP) {
+ if (filestr[strlen(filestr) - 1] == SEP) {
/* Directory */
filepos = 0;
- d = opendir(filestr);
+ d = opendir(filestr);
if (d != NULL) {
- printf("DIR:'%s' %8d %8d\n", d->dd_name, d->dd_fd,
- d->dd_sect);
+ //printf("DIR:'%s' %08x %8d\n", d->dd_name, (int)d->dd_sect, d->dd_offset);
de = readdir(d);
while (de != NULL) {
filepos++;
#ifdef DO_DEBUG
// if (strlen(de->d_name) > 25) de->d_name[25] = 0;
- switch (de->d_mode) {
+ switch (de->d_type) {
case 16:
ty = 'D';
break;
@@ -445,8 +444,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
default:
ty = '*';
}
- printf("@%8d:%8d:%4d ", (int)de->d_ino, (int)de->d_size,
- de->d_mode);
#endif /* DO_DEBUG */
// printf("%s\n", de->d_name);
printf("'%s'\n", de->d_name);
@@ -458,7 +455,6 @@ void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
de = readdir(d);
// if(filepos>15){ de = NULL; printf("Force Break\n");}
}
- printf("Dir.dd_fd: '%8d'\n", d->dd_fd);
closedir(d);
} else {
rosh_error(0, "dir:NULL", filestr);
diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h
index 64b0564c..0c41bac9 100644
--- a/com32/rosh/rosh.h
+++ b/com32/rosh/rosh.h
@@ -47,6 +47,8 @@
#error SYSLINUX (I believe) requires __GNUC__
#endif /* __GNUC__ */
+#define DO_DEBUG 1
+
#ifdef DO_DEBUG
#define ROSH_DEBUG(f, ...) printf (f, ## __VA_ARGS__)
#ifdef DO_DEBUG2
diff --git a/com32/tools/.gitignore b/com32/tools/.gitignore
new file mode 100644
index 00000000..b5397de4
--- /dev/null
+++ b/com32/tools/.gitignore
@@ -0,0 +1 @@
+/relocs
diff --git a/com32/tools/Makefile b/com32/tools/Makefile
new file mode 100644
index 00000000..3665f84b
--- /dev/null
+++ b/com32/tools/Makefile
@@ -0,0 +1,30 @@
+## -*- makefile -*- ------------------------------------------------------
+##
+## Copyright 2001-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.
+##
+## -----------------------------------------------------------------------
+
+topdir = ../..
+include $(topdir)/MCONFIG.build
+
+BINS = relocs
+
+all : $(BINS)
+
+relocs : relocs.o
+ $(CC) $(LDFLAGS) -o $@ $^ $(LIBS)
+
+tidy dist clean spotless:
+ rm -f $(BINS)
+ rm -f *.o *.a .*.d
+ rm -f */*.o */*.a */.*.d
+
+installer:
+
+-include .*.d */.*.d
diff --git a/com32/tools/relocs.c b/com32/tools/relocs.c
new file mode 100644
index 00000000..be57bf7e
--- /dev/null
+++ b/com32/tools/relocs.c
@@ -0,0 +1,693 @@
+/*
+ * This file is taken from the Linux kernel and is distributed under GPL v2.
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <elf.h>
+#include <byteswap.h>
+#define USE_BSD
+#include <endian.h>
+#include <regex.h>
+#include <sys/types.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+static Elf32_Ehdr ehdr;
+static unsigned long reloc_count, reloc_idx;
+static unsigned long *relocs;
+
+struct section {
+ Elf32_Shdr shdr;
+ struct section *link;
+ Elf32_Sym *symtab;
+ Elf32_Rel *reltab;
+ char *strtab;
+};
+static struct section *secs;
+
+static void die(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+/*
+ * Following symbols have been audited. Don't warn user about
+ * absolute relocations present w.r.t these symbols.
+ */
+
+/* True absolute relocations */
+
+static const char safe_abs_regex[] =
+"^(__.*_len|__.*_dwords)$";
+static regex_t safe_abs_regex_c;
+
+static int is_safe_abs_reloc(const char *sym_name)
+{
+ return !regexec(&safe_abs_regex_c, sym_name, 0, NULL, 0);
+}
+
+/* These are relative even though the linker marks them absolute */
+
+static const char safe_rel_regex[] =
+"^(__.*_start|__.*_end|_end|_[se](text|data))$";
+static regex_t safe_rel_regex_c;
+
+static int is_safe_rel_reloc(const char *sym_name)
+{
+ return !regexec(&safe_rel_regex_c, sym_name, 0, NULL, 0);
+}
+
+static void regex_init(void)
+{
+ char errbuf[128];
+ int err;
+
+ err = regcomp(&safe_abs_regex_c, safe_abs_regex,
+ REG_EXTENDED|REG_NOSUB);
+ if (err) {
+ regerror(err, &safe_abs_regex_c, errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
+
+ err = regcomp(&safe_rel_regex_c, safe_rel_regex,
+ REG_EXTENDED|REG_NOSUB);
+ if (err) {
+ regerror(err, &safe_rel_regex_c, errbuf, sizeof errbuf);
+ die("%s", errbuf);
+ }
+}
+
+static const char *sym_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define SYM_TYPE(X) [X] = #X
+ SYM_TYPE(STT_NOTYPE),
+ SYM_TYPE(STT_OBJECT),
+ SYM_TYPE(STT_FUNC),
+ SYM_TYPE(STT_SECTION),
+ SYM_TYPE(STT_FILE),
+ SYM_TYPE(STT_COMMON),
+ SYM_TYPE(STT_TLS),
+#undef SYM_TYPE
+ };
+ const char *name = "unknown sym type name";
+ if (type < ARRAY_SIZE(type_name)) {
+ name = type_name[type];
+ }
+ return name;
+}
+
+static const char *sym_bind(unsigned bind)
+{
+ static const char *bind_name[] = {
+#define SYM_BIND(X) [X] = #X
+ SYM_BIND(STB_LOCAL),
+ SYM_BIND(STB_GLOBAL),
+ SYM_BIND(STB_WEAK),
+#undef SYM_BIND
+ };
+ const char *name = "unknown sym bind name";
+ if (bind < ARRAY_SIZE(bind_name)) {
+ name = bind_name[bind];
+ }
+ return name;
+}
+
+static const char *sym_visibility(unsigned visibility)
+{
+ static const char *visibility_name[] = {
+#define SYM_VISIBILITY(X) [X] = #X
+ SYM_VISIBILITY(STV_DEFAULT),
+ SYM_VISIBILITY(STV_INTERNAL),
+ SYM_VISIBILITY(STV_HIDDEN),
+ SYM_VISIBILITY(STV_PROTECTED),
+#undef SYM_VISIBILITY
+ };
+ const char *name = "unknown sym visibility name";
+ if (visibility < ARRAY_SIZE(visibility_name)) {
+ name = visibility_name[visibility];
+ }
+ return name;
+}
+
+static const char *rel_type(unsigned type)
+{
+ static const char *type_name[] = {
+#define REL_TYPE(X) [X] = #X
+ REL_TYPE(R_386_NONE),
+ REL_TYPE(R_386_32),
+ REL_TYPE(R_386_PC32),
+ REL_TYPE(R_386_GOT32),
+ REL_TYPE(R_386_PLT32),
+ REL_TYPE(R_386_COPY),
+ REL_TYPE(R_386_GLOB_DAT),
+ REL_TYPE(R_386_JMP_SLOT),
+ REL_TYPE(R_386_RELATIVE),
+ REL_TYPE(R_386_GOTOFF),
+ REL_TYPE(R_386_GOTPC),
+#undef REL_TYPE
+ };
+ const char *name = NULL;
+ if (type < ARRAY_SIZE(type_name))
+ name = type_name[type];
+ if (!name)
+ name = "unknown";
+ return name;
+}
+
+static const char *sec_name(unsigned shndx)
+{
+ const char *sec_strtab;
+ const char *name;
+ sec_strtab = secs[ehdr.e_shstrndx].strtab;
+ name = "<noname>";
+ if (shndx < ehdr.e_shnum) {
+ name = sec_strtab + secs[shndx].shdr.sh_name;
+ }
+ else if (shndx == SHN_ABS) {
+ name = "ABSOLUTE";
+ }
+ else if (shndx == SHN_COMMON) {
+ name = "COMMON";
+ }
+ return name;
+}
+
+static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
+{
+ const char *name;
+ name = "<noname>";
+ if (sym->st_name) {
+ name = sym_strtab + sym->st_name;
+ }
+ else {
+ name = sec_name(secs[sym->st_shndx].shdr.sh_name);
+ }
+ return name;
+}
+
+
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+#define le16_to_cpu(val) bswap_16(val)
+#define le32_to_cpu(val) bswap_32(val)
+#endif
+
+static uint16_t elf16_to_cpu(uint16_t val)
+{
+ return le16_to_cpu(val);
+}
+
+static uint32_t elf32_to_cpu(uint32_t val)
+{
+ return le32_to_cpu(val);
+}
+
+static void read_ehdr(FILE *fp)
+{
+ if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
+ die("Cannot read ELF header: %s\n",
+ strerror(errno));
+ }
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
+ die("No ELF magic\n");
+ }
+ if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
+ die("Not a 32 bit executable\n");
+ }
+ if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
+ die("Not a LSB ELF executable\n");
+ }
+ if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ /* Convert the fields to native endian */
+ ehdr.e_type = elf16_to_cpu(ehdr.e_type);
+ ehdr.e_machine = elf16_to_cpu(ehdr.e_machine);
+ ehdr.e_version = elf32_to_cpu(ehdr.e_version);
+ ehdr.e_entry = elf32_to_cpu(ehdr.e_entry);
+ ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff);
+ ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff);
+ ehdr.e_flags = elf32_to_cpu(ehdr.e_flags);
+ ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize);
+ ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
+ ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum);
+ ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
+ ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum);
+ ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx);
+
+ if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
+ die("Unsupported ELF header type\n");
+ }
+ if (ehdr.e_machine != EM_386) {
+ die("Not for x86\n");
+ }
+ if (ehdr.e_version != EV_CURRENT) {
+ die("Unknown ELF version\n");
+ }
+ if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
+ die("Bad Elf header size\n");
+ }
+ if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
+ die("Bad program header entry\n");
+ }
+ if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
+ die("Bad section header entry\n");
+ }
+ if (ehdr.e_shstrndx >= ehdr.e_shnum) {
+ die("String table index out of bounds\n");
+ }
+}
+
+static void read_shdrs(FILE *fp)
+{
+ int i;
+ Elf32_Shdr shdr;
+
+ secs = calloc(ehdr.e_shnum, sizeof(struct section));
+ if (!secs) {
+ die("Unable to allocate %d section headers\n",
+ ehdr.e_shnum);
+ }
+ if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ ehdr.e_shoff, strerror(errno));
+ }
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (fread(&shdr, sizeof shdr, 1, fp) != 1)
+ die("Cannot read ELF section headers %d/%d: %s\n",
+ i, ehdr.e_shnum, strerror(errno));
+ sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name);
+ sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type);
+ sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags);
+ sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr);
+ sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset);
+ sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size);
+ sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link);
+ sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info);
+ sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
+ sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize);
+ if (sec->shdr.sh_link < ehdr.e_shnum)
+ sec->link = &secs[sec->shdr.sh_link];
+ }
+
+}
+
+static void read_strtabs(FILE *fp)
+{
+ int i;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_STRTAB) {
+ continue;
+ }
+ sec->strtab = malloc(sec->shdr.sh_size);
+ if (!sec->strtab) {
+ die("malloc of %d bytes for strtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ }
+}
+
+static void read_symtabs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sec->symtab = malloc(sec->shdr.sh_size);
+ if (!sec->symtab) {
+ die("malloc of %d bytes for symtab failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym = &sec->symtab[j];
+ sym->st_name = elf32_to_cpu(sym->st_name);
+ sym->st_value = elf32_to_cpu(sym->st_value);
+ sym->st_size = elf32_to_cpu(sym->st_size);
+ sym->st_shndx = elf16_to_cpu(sym->st_shndx);
+ }
+ }
+}
+
+
+static void read_relocs(FILE *fp)
+{
+ int i,j;
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec->reltab = malloc(sec->shdr.sh_size);
+ if (!sec->reltab) {
+ die("malloc of %d bytes for relocs failed\n",
+ sec->shdr.sh_size);
+ }
+ if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
+ die("Seek to %d failed: %s\n",
+ sec->shdr.sh_offset, strerror(errno));
+ }
+ if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
+ != sec->shdr.sh_size) {
+ die("Cannot read symbol table: %s\n",
+ strerror(errno));
+ }
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel = &sec->reltab[j];
+ rel->r_offset = elf32_to_cpu(rel->r_offset);
+ rel->r_info = elf32_to_cpu(rel->r_info);
+ }
+ }
+}
+
+
+static void print_absolute_symbols(void)
+{
+ int i;
+ printf("Absolute symbols\n");
+ printf(" Num: Value Size Type Bind Visibility Name\n");
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ int j;
+
+ if (sec->shdr.sh_type != SHT_SYMTAB) {
+ continue;
+ }
+ sh_symtab = sec->symtab;
+ sym_strtab = sec->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
+ Elf32_Sym *sym;
+ const char *name;
+ sym = &sec->symtab[j];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+ printf("%5d %08x %5d %10s %10s %12s %s\n",
+ j, sym->st_value, sym->st_size,
+ sym_type(ELF32_ST_TYPE(sym->st_info)),
+ sym_bind(ELF32_ST_BIND(sym->st_info)),
+ sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
+ name);
+ }
+ }
+ printf("\n");
+}
+
+static int print_absolute_relocs(FILE *f)
+{
+ int i, printed = 0;
+
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ struct section *sec = &secs[i];
+ struct section *sec_applies, *sec_symtab;
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ int j;
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ const char *name;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ name = sym_name(sym_strtab, sym);
+ if (sym->st_shndx != SHN_ABS) {
+ continue;
+ }
+
+ /* Absolute symbols are not relocated if bzImage is
+ * loaded at a non-compiled address. Display a warning
+ * to user at compile time about the absolute
+ * relocations present.
+ *
+ * User need to audit the code to make sure
+ * some symbols which should have been section
+ * relative have not become absolute because of some
+ * linker optimization or wrong programming usage.
+ *
+ * Before warning check if this absolute symbol
+ * relocation is harmless.
+ */
+ if (is_safe_abs_reloc(name) ||
+ is_safe_rel_reloc(name))
+ continue;
+
+ if (!printed) {
+ fprintf(f, "Unknown absolute relocations present\n");
+ fprintf(f, "Offset Info Type Sym.Value Sym.Name\n");
+ printed = 1;
+ }
+
+ fprintf(f, "%08x %08x %10s %08x %s\n",
+ rel->r_offset,
+ rel->r_info,
+ rel_type(ELF32_R_TYPE(rel->r_info)),
+ sym->st_value,
+ name);
+ }
+ }
+
+ if (printed)
+ fputc('\n', f);
+
+ return printed;
+}
+
+static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym))
+{
+ int i;
+ /* Walk through the relocations */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ char *sym_strtab;
+ Elf32_Sym *sh_symtab;
+ struct section *sec_applies, *sec_symtab;
+ int j;
+ struct section *sec = &secs[i];
+
+ if (sec->shdr.sh_type != SHT_REL) {
+ continue;
+ }
+ sec_symtab = sec->link;
+ sec_applies = &secs[sec->shdr.sh_info];
+ if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
+ continue;
+ }
+ sh_symtab = sec_symtab->symtab;
+ sym_strtab = sec_symtab->link->strtab;
+ for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
+ Elf32_Rel *rel;
+ Elf32_Sym *sym;
+ unsigned r_type;
+ rel = &sec->reltab[j];
+ sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
+ r_type = ELF32_R_TYPE(rel->r_info);
+ /* Don't visit relocations to absolute symbols */
+ if (sym->st_shndx == SHN_ABS &&
+ !is_safe_rel_reloc(sym_name(sym_strtab, sym)))
+ continue;
+
+ switch (r_type) {
+ case R_386_NONE:
+ case R_386_PC32:
+ case R_386_GOTPC:
+ case R_386_GOTOFF:
+ case R_386_GOT32:
+ case R_386_PLT32:
+ /* Relative relocations don't need to
+ be adjusted */
+ break;
+ case R_386_32:
+ /* Visit relocations that need adjustment */
+ visit(rel, sym);
+ break;
+ default:
+ die("Unsupported relocation type: %s (%d)\n",
+ rel_type(r_type), r_type);
+ }
+ }
+ }
+}
+
+static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ (void)rel; (void)sym;
+ reloc_count += 1;
+}
+
+static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
+{
+ (void)sym;
+
+ /* Remember the address that needs to be adjusted. */
+ relocs[reloc_idx++] = rel->r_offset;
+}
+
+static int cmp_relocs(const void *va, const void *vb)
+{
+ const unsigned long *a, *b;
+ a = va; b = vb;
+ return (*a == *b)? 0 : (*a > *b)? 1 : -1;
+}
+
+static void emit_relocs(int as_text)
+{
+ int i;
+ /* Count how many relocations I have and allocate space for them. */
+ reloc_count = 0;
+ walk_relocs(count_reloc);
+ relocs = malloc(reloc_count * sizeof(relocs[0]));
+ if (!relocs) {
+ die("malloc of %d entries for relocs failed\n",
+ reloc_count);
+ }
+ /* Collect up the relocations */
+ reloc_idx = 0;
+ walk_relocs(collect_reloc);
+
+ /* Order the relocations for more efficient processing */
+ qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
+
+ /* Print the relocations */
+ if (as_text) {
+ /* Print the relocations in a form suitable that
+ * gas will like.
+ */
+ printf(".section \".data.reloc\",\"a\"\n");
+ printf(".balign 4\n");
+ for (i = 0; i < reloc_count; i++) {
+ printf("\t .long 0x%08lx\n", relocs[i]);
+ }
+ printf("\n");
+ }
+ else {
+ unsigned char buf[4];
+ /* Now print each relocation */
+ for (i = 0; i < reloc_count; i++) {
+ buf[0] = (relocs[i] >> 0) & 0xff;
+ buf[1] = (relocs[i] >> 8) & 0xff;
+ buf[2] = (relocs[i] >> 16) & 0xff;
+ buf[3] = (relocs[i] >> 24) & 0xff;
+ fwrite(buf, 4, 1, stdout);
+ }
+ /* Print a stop */
+ memset(buf, 0, sizeof buf);
+ fwrite(buf, 4, 1, stdout);
+ }
+}
+
+static void usage(void)
+{
+ die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n");
+}
+
+int main(int argc, char **argv)
+{
+ int show_absolute_syms, show_absolute_relocs;
+ int as_text;
+ const char *fname;
+ FILE *fp;
+ int i;
+ int err = 0;
+
+ show_absolute_syms = 0;
+ show_absolute_relocs = 0;
+ as_text = 0;
+ fname = NULL;
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+ if (*arg == '-') {
+ if (strcmp(argv[1], "--abs-syms") == 0) {
+ show_absolute_syms = 1;
+ continue;
+ }
+
+ if (strcmp(argv[1], "--abs-relocs") == 0) {
+ show_absolute_relocs = 1;
+ continue;
+ }
+ else if (strcmp(argv[1], "--text") == 0) {
+ as_text = 1;
+ continue;
+ }
+ }
+ else if (!fname) {
+ fname = arg;
+ continue;
+ }
+ usage();
+ }
+ if (!fname) {
+ usage();
+ }
+
+
+ regex_init();
+
+ fp = fopen(fname, "r");
+ if (!fp) {
+ die("Cannot open %s: %s\n",
+ fname, strerror(errno));
+ }
+ read_ehdr(fp);
+ read_shdrs(fp);
+ read_strtabs(fp);
+ read_symtabs(fp);
+ read_relocs(fp);
+ if (show_absolute_syms) {
+ print_absolute_symbols();
+ return 0;
+ }
+ if (show_absolute_relocs) {
+ print_absolute_relocs(stdout);
+ return 0;
+ }
+ err = print_absolute_relocs(stderr);
+ emit_relocs(as_text);
+ return err;
+}
diff --git a/core/Makefile b/core/Makefile
index 65418c48..d35390f4 100644
--- a/core/Makefile
+++ b/core/Makefile
@@ -23,8 +23,8 @@ topdir = ..
include $(topdir)/MCONFIG.embedded
-include $(topdir)/version.mk
-OPTFLAGS =
-INCLUDES =
+OPTFLAGS =
+INCLUDES = -I./include -I$(com32)/include
# This is very similar to cp437; technically it's for Norway and Denmark,
# but it's unlikely the characters that are different will be used in
@@ -33,17 +33,30 @@ CODEPAGE = cp865
# The targets to build in this directory...
BTARGET = kwdhash.gen \
+ extlinux.bin extlinux.bss extlinux.sys \
ldlinux.bss ldlinux.sys ldlinux.bin \
- pxelinux.0 isolinux.bin isolinux-debug.bin \
- extlinux.bin extlinux.bss extlinux.sys
+ isolinux.bin isolinux-debug.bin pxelinux.0
# All primary source files for the main syslinux files
-NASMSRC = $(wildcard *.asm)
-NASMHDR = $(wildcard *.inc)
-CSRC = $(wildcard *.c)
-CHDR = $(wildcard *.h)
-OTHERSRC = keywords
-ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(CHDR) $(OTHERSRC)
+NASMSRC := $(wildcard *.asm)
+NASMHDR := $(wildcard *.inc)
+CSRC := $(wildcard *.c */*.c */*/*.c)
+SSRC := $(wildcard *.S */*.S */*/*.S)
+CHDR := $(wildcard *.h)
+OTHERSRC := keywords
+ALLSRC = $(NASMSRC) $(NASMHDR) $(CSRC) $(SSRC) $(CHDR) $(OTHERSRC)
+
+COBJ := $(patsubst %.c,%.o,$(CSRC))
+SOBJ := $(patsubst %.S,%.o,$(SSRC))
+
+LIB = libcore.a
+LIBS = $(LIB) $(com32)/lib/libcom32.a $(LIBGCC)
+LIBOBJS = $(COBJ) $(SOBJ)
+
+NASMDEBUG = -g -F dwarf
+NASMOPT += $(NASMDEBUG)
+
+PREPCORE = ../lzo/prepcore
# The DATE is set on the make command line when building binaries for
# official release. Otherwise, substitute a hex string that is pretty much
@@ -62,26 +75,28 @@ kwdhash.gen: keywords genhash.pl
.PRECIOUS: %.elf
-# Standard rule for {isolinux,isolinux-debug}.bin
-iso%.bin: iso%.elf checksumiso.pl
- $(OBJCOPY) -O binary $< $@
- $(PERL) checksumiso.pl $@
+%.raw: %.elf
+ $(OBJCOPY) -O binary $< $(@:.bin=.raw)
-# Standard rule for {ldlinux,pxelinux,extlinux}.bin
-%.bin: %.elf
- $(OBJCOPY) -O binary $< $@
+%.bin: %.raw $(PREPCORE)
+ $(PREPCORE) $< $@
%.o: %.asm kwdhash.gen ../version.gen
- ( $(NASM) -M -DDEPEND $(NINCLUDE) -o $@ $< ; echo '' ) > .$@.d; true
- $(NASM) $(NASMOPT) -f elf -g -F stabs -DDATE_STR="'$(DATE)'" \
+ $(NASM) -f elf $(NASMOPT) -DDATE_STR="'$(DATE)'" \
-DHEXDATE="$(HEXDATE)" \
- -l $(@:.o=.lsr) -o $@ $<
+ -l $(@:.o=.lsr) -o $@ -MP -MD .$@.d $<
-%.elf: %.o syslinux.ld
- $(LD) $(LDFLAGS) -T syslinux.ld -M -o $@ $< > $(@:.elf=.map)
+%.elf: %.o $(LIBS) syslinux.ld
+ $(LD) $(LDFLAGS) -T syslinux.ld -M -o $@ $< $(LIBS) \
+ > $(@:.elf=.map)
$(OBJDUMP) -h $@ > $(@:.elf=.sec)
$(PERL) lstadjust.pl $(@:.elf=.lsr) $(@:.elf=.sec) $(@:.elf=.lst)
+$(LIB): $(LIBOBJS)
+ rm -f $@
+ $(AR) cq $@ $^
+ $(RANLIB) $@
+
pxelinux.0: pxelinux.bin
cp -f $< $@
@@ -112,8 +127,10 @@ install-all: install install-lib
netinstall: installer
tidy dist:
- rm -f codepage.cp *.o *.elf stupid.* patch.offset .depend .*.d
- rm -f *.lsr *.lst *.map *.sec
+ rm -f codepage.cp *.o *.elf *.a stupid.* patch.offset .depend .*.d
+ rm -f *.elf.tmp *.sym
+ rm -f *.lsr *.lst *.map *.sec *.raw
+ rm -f */*.o */*/*.o */*.lst */*/*.lst */.*.d */*/.*.d
rm -f $(OBSOLETE)
clean: tidy
@@ -122,4 +139,4 @@ spotless: clean
rm -f $(BTARGET) *.bin *_bin.c
# Include dependencies file
--include .*.d
+-include .*.d */.*.d
diff --git a/core/abort.inc b/core/abort.inc
index 5b16b9d9..9b181363 100644
--- a/core/abort.inc
+++ b/core/abort.inc
@@ -17,7 +17,7 @@
; Code to terminate a kernel load
;
- section .text
+ section .text16
;
; dot_pause: same as abort_check, except prints a dot, too
@@ -78,7 +78,7 @@ error_or_command:
jnz on_error
jmp enter_command
- section .data
+ section .data16
aborted_msg db ' aborted.', CR, LF, 0
- section .text
+ section .text16
diff --git a/core/adv.inc b/core/adv.inc
index d856a1a2..2dc16339 100644
--- a/core/adv.inc
+++ b/core/adv.inc
@@ -57,7 +57,7 @@ adv1:
.data resb ADV_LEN
.tail resd 1
.end equ $
- section .text
+ section .text16
;
; This is called after config file parsing, so we know
@@ -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
@@ -492,12 +494,14 @@ adv_read_write:
stc
jmp .cb_done
- section .data
+ section .data16
alignz 4
ADVSec0 dd 0 ; Not specified
ADVSec1 dd 0 ; Not specified
ADVDrive db -1 ; No ADV defined
ADVCHSInfo db -1 ; We have CHS info for this drive
- section .bss
+ section .bss16
ADVOp resb 1
+
+ section .text16
diff --git a/core/bcopy32.inc b/core/bcopy32.inc
index c363373a..6537546b 100644
--- a/core/bcopy32.inc
+++ b/core/bcopy32.inc
@@ -29,7 +29,7 @@
;
bits 16
- section .text
+ section .text16
;
; bcopy:
@@ -39,17 +39,13 @@
; ESI - source pointer (-1 means do bzero rather than bcopy)
; EDI - target pointer
; ECX - byte count
-; DF - zero
;
; Outputs:
; ESI - first byte after source (garbage if ESI == -1 on entry)
; EDI - first byte after target
;
bcopy: jecxz .ret
- pushad
- push word pm_bcopy
- call simple_pm_call
- popad
+ pm_call pm_bcopy
add edi,ecx
add esi,ecx
.ret: ret
@@ -70,293 +66,8 @@ bcopy: jecxz .ret
; the entry point and src the mode (0 = pm, 1 = rm)
;
shuffle_and_boot_raw:
- push word pm_shuffle
- call simple_pm_call
- ; Never returns...
- jmp kaboom
-
-;
-; This routine is used to invoke a simple routine in 32-bit protected
-; mode (with 32-bit zero-based CS, DS, ES, and SS, with ESP pointing to the
-; real-mode stack even if the real-mode stack was in a nonzero SS.)
-;
-; No interrupt thunking services are provided; interrupts are disabled
-; for the duration of the routine. Don't run for too long at a time
-; unless you really mean it.
-;
-; Inputs:
-; On stack - pm entrypoint (IP only)
-; EAX, EBP preserved until real-mode exit
-; EBX, ECX, EDX, ESI and EDI passed to the called routine
-;
-; Outputs:
-; EAX, EBP restored from real-mode entry
-; All other registers as returned from called function
-; PM entrypoint cleaned off stack
-;
-simple_pm_call:
- push eax
- push ebp
- movzx ebp,sp ; BP is used as frame pointer
- pushfd ; Saves, among others, the IF flag
- push ds
- push es
- push fs
- push gs
-
- cli
- call enable_a20
-
- mov byte [cs:bcopy_gdt.TSS+5],89h ; Mark TSS unbusy
-
- ; Convert the stack segment to a base
- xor eax,eax
- mov ax,ss
- shl eax,4
- add ebp,eax ; EBP is now an absolute frame ptr
-
- ; Save the old segmented stack pointer
- mov [cs:.rm_esp],esp
- mov [cs:.rm_ss],ss
-
- o32 lgdt [cs:bcopy_gdt]
- mov eax,cr0
- or al,1
- mov cr0,eax ; Enter protected mode
- jmp PM_CS32:.in_pm
-
- bits 32
-.in_pm:
- mov ax,PM_DS32
- mov ss,eax
- lea esp,[ebp-8*4-2*4] ; Flat mode stack
- mov es,eax
- mov ds,eax
-
- ; Set fs, gs, tr, and ldtr in case we're on a virtual
- ; machine running on Intel VT hardware -- it can't
- ; deal with a partial transition, for no good reason.
-
- mov al,PM_DS16 ; Real-mode-like segment
- mov fs,eax
- mov gs,eax
- mov al,PM_TSS ; Intel VT really doesn't want
- ltr ax ; an invalid TR and LDTR, so give
- xor eax,eax ; it something that it can use...
- lldt ax ; (sigh)
-
- movzx eax,word [ebp+2*4+2]
- call eax ; Call actual routine
-
- jmp PM_CS16:.exit
- bits 16
-.exit:
- mov ax,PM_DS16 ; "Real-mode-like" data segment
- mov es,eax
- mov ds,eax
- mov ss,eax
-
- mov eax,cr0
- and al,~1
- mov cr0,eax ; Disable protected mode
- jmp 0:.in_rm
-
-.in_rm: ; Back in real mode
- lss esp,[cs:.rm_esp] ; Restore the stack
- pop gs
- pop fs
- pop es
- pop ds
-
- popfd ; Re-enables interrupts
- pop ebp
- pop eax
- ret 2 ; Drops the pm entry
-
- section .bss
- alignb 4
-.rm_esp resd 1
-.rm_ss resw 1
-
-
- section .text
-;
-; Routines to enable and disable (yuck) A20. These routines are gathered
-; from tips from a couple of sources, including the Linux kernel and
-; http://www.x86.org/. The need for the delay to be as large as given here
-; is indicated by Donnie Barnes of RedHat, the problematic system being an
-; IBM ThinkPad 760EL.
-;
-
- section .data
- alignz 2
-A20Ptr dw a20_dunno
-
- section .bss
- alignb 4
-A20Test resd 1 ; Counter for testing A20 status
-A20Tries resb 1 ; Times until giving up on A20
-
- section .text
-enable_a20:
- pushad
- mov byte [cs:A20Tries],255 ; Times to try to make this work
-
-try_enable_a20:
-
-;
-; First, see if we are on a system with no A20 gate, or the A20 gate
-; is already enabled for us...
-;
-a20_none:
- call a20_test
- jnz a20_done
- ; Otherwise, see if we had something memorized...
- jmp word [cs:A20Ptr]
-
-;
-; Next, try the BIOS (INT 15h AX=2401h)
-;
-a20_dunno:
-a20_bios:
- mov word [cs:A20Ptr], a20_bios
- mov ax,2401h
- pushf ; Some BIOSes muck with IF
- int 15h
- popf
-
- call a20_test
- jnz a20_done
-
-;
-; Enable the keyboard controller A20 gate
-;
-a20_kbc:
- mov dl, 1 ; Allow early exit
- call empty_8042
- jnz a20_done ; A20 live, no need to use KBC
-
- mov word [cs:A20Ptr], a20_kbc ; Starting KBC command sequence
-
- mov al,0D1h ; Write output port
- out 064h, al
- call empty_8042_uncond
-
- mov al,0DFh ; A20 on
- out 060h, al
- call empty_8042_uncond
-
- ; Apparently the UHCI spec assumes that A20 toggle
- ; ends with a null command (assumed to be for sychronization?)
- ; Put it here to see if it helps anything...
- mov al,0FFh ; Null command
- out 064h, al
- call empty_8042_uncond
-
- ; Verify that A20 actually is enabled. Do that by
- ; observing a word in low memory and the same word in
- ; the HMA until they are no longer coherent. Note that
- ; we don't do the same check in the disable case, because
- ; we don't want to *require* A20 masking (SYSLINUX should
- ; work fine without it, if the BIOS does.)
-.kbc_wait: push cx
- xor cx,cx
-.kbc_wait_loop:
- call a20_test
- jnz a20_done_pop
- loop .kbc_wait_loop
-
- pop cx
-;
-; Running out of options here. Final attempt: enable the "fast A20 gate"
-;
-a20_fast:
- mov word [cs:A20Ptr], a20_fast
- in al, 092h
- or al,02h
- and al,~01h ; Don't accidentally reset the machine!
- out 092h, al
-
-.fast_wait: push cx
- xor cx,cx
-.fast_wait_loop:
- call a20_test
- jnz a20_done_pop
- loop .fast_wait_loop
-
- pop cx
-
-;
-; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
-; and report failure to the user.
-;
- dec byte [cs:A20Tries]
- jnz a20_dunno ; Did we get the wrong type?
-
- mov si, err_a20
- jmp abort_load
-
- section .data
-err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
- section .text
-
-;
-; A20 unmasked, proceed...
-;
-a20_done_pop: pop cx
-a20_done: popad
- ret
-
-;
-; This routine tests if A20 is enabled (ZF = 0). This routine
-; must not destroy any register contents.
-;
-; The no-write early out avoids the io_delay in the (presumably common)
-; case of A20 already enabled (e.g. from a previous call.)
-;
-a20_test:
- push es
- push cx
- push eax
- mov cx,0FFFFh ; HMA = segment 0FFFFh
- mov es,cx
- mov eax,[cs:A20Test]
- mov cx,32 ; Loop count
- jmp .test ; First iteration = early out
-.wait: add eax,0x430aea41 ; A large prime number
- mov [cs:A20Test],eax
- io_delay ; Serialize, and fix delay
-.test: cmp eax,[es:A20Test+10h]
- loopz .wait
-.done: pop eax
- pop cx
- pop es
- ret
-
-;
-; Routine to empty the 8042 KBC controller. If dl != 0
-; then we will test A20 in the loop and exit if A20 is
-; suddenly enabled.
-;
-empty_8042_uncond:
- xor dl,dl
-empty_8042:
- call a20_test
- jz .a20_on
- and dl,dl
- jnz .done
-.a20_on: io_delay
- in al, 064h ; Status port
- test al,1
- jz .no_output
- io_delay
- in al, 060h ; Read input
- jmp short empty_8042
-.no_output:
- test al,2
- jnz empty_8042
- io_delay
-.done: ret
+ mov bx,pm_shuffle
+ jmp enter_pm
;
; The 32-bit copy and shuffle code is "special", so it is in its own file
diff --git a/core/bcopyxx.inc b/core/bcopyxx.inc
index 89ae4f40..823662b4 100644
--- a/core/bcopyxx.inc
+++ b/core/bcopyxx.inc
@@ -204,6 +204,7 @@ pm_bcopy:
; the entry point and src the mode (0 = pm, 1 = rm)
;
pm_shuffle:
+ cli ; End interrupt service (for good)
mov ebx,edi ; EBX <- descriptor list
lea edx,[edi+ecx+15] ; EDX <- where to relocate our code to
and edx,~15 ; Align 16 to benefit the GDT
@@ -232,15 +233,16 @@ pm_shuffle:
call pm_bcopy
jmp .loop
.done:
+ lidt [edx+RM_IDT_ptr-bcopy_gdt] ; RM-like IDT
push ecx ; == 0, for cleaning the flags register
and esi,esi
- jz pm_shuffle_real_mode
+ jz pm_shuffle_16
popfd ; Clean the flags
jmp edi ; Protected mode entry
- ; We have a real-mode entry point, so we need to return
- ; to real mode. Note: EDX already points to the GDT.
-pm_shuffle_real_mode:
+ ; We have a 16-bit entry point, so we need to return
+ ; to 16-bit mode. Note: EDX already points to the GDT.
+pm_shuffle_16:
mov eax,edi
mov [edx+PM_CS16+2],ax
mov [edx+PM_DS16+2],ax
@@ -261,7 +263,11 @@ pm_shuffle_real_mode:
mov ss,edx
jmp PM_CS16:0
- align 16
+ align 4
+RM_IDT_ptr: dw 0FFFFh ; Length (nonsense, but matches CPU)
+ dd 0 ; Offset
+
+ alignz 16
; GDT descriptor entry
%macro desc 1
bcopy_gdt.%1:
@@ -312,4 +318,4 @@ bcopyxx_safe equ bcopyxx_len + bcopyxx_stack + 15
DummyTSS equ 0x580
bits 16
- section .text
+ section .text16
diff --git a/core/bios.inc b/core/bios.inc
index 987a2166..33a3cd4c 100644
--- a/core/bios.inc
+++ b/core/bios.inc
@@ -18,11 +18,17 @@
%ifndef _BIOS_INC
%define _BIOS_INC
+ global BIOS_fbm, BIOS_timer
- absolute 4*1Eh ; In the interrupt table
+ ; Interrupt vectors
+ absolute 4*1Ch
+BIOS_timer_hook resd 1
+
+ absolute 4*1Eh
fdctab equ $
fdctab1 resw 1
fdctab2 resw 1
+
absolute 0400h
serial_base resw 4 ; Base addresses for 4 serial ports
absolute 0413h
diff --git a/core/bootsect.inc b/core/bootsect.inc
index 200f00ad..23b4fdb4 100644
--- a/core/bootsect.inc
+++ b/core/bootsect.inc
@@ -80,7 +80,7 @@ load_bootsec:
xor bx,bx
%elif IS_PXELINUX
mov byte [KeepPXE],03h ; Chainloading + keep PXE
- call reset_pxe
+ pm_call reset_pxe
lfs si,[InitStack]
; Put restore DS, EDX and ESI to the true initial values
mov bx,[fs:si+6]
@@ -137,7 +137,9 @@ replace_bootstrap:
jmp .stackok
%endif
.stdstack:
- mov di,7C00h-44
+ ; StackBuf is guaranteed to have 44 bytes free immediately
+ ; above it, and it will not interfere with our existing stack.
+ mov di,StackBuf
push di
mov cx,22 ; 44 bytes
rep stosw
@@ -226,4 +228,4 @@ replace_stub:
jmp 0:0
.csip equ $-4
- section .text
+ section .text16
diff --git a/core/cache.c b/core/cache.c
new file mode 100644
index 00000000..415becff
--- /dev/null
+++ b/core/cache.c
@@ -0,0 +1,134 @@
+/*
+ * core/cache.c: A simple LRU-based cache implementation.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "core.h"
+#include "cache.h"
+
+
+/*
+ * Initialize the cache data structres. the _block_size_shift_ specify
+ * the block size, which is 512 byte for FAT fs of the current
+ * implementation since the block(cluster) size in FAT is a bit big.
+ *
+ */
+void cache_init(struct device *dev, int block_size_shift)
+{
+ struct cache_struct *prev, *cur;
+ char *data = dev->cache_data;
+ static __lowmem struct cache_struct cache_head, cache[MAX_CACHE_ENTRIES];
+ int i;
+
+ dev->cache_head = &cache_head;
+ dev->cache_block_size = 1 << block_size_shift;
+ dev->cache_entries = dev->cache_size >> block_size_shift;
+ if (dev->cache_entries > MAX_CACHE_ENTRIES)
+ dev->cache_entries = MAX_CACHE_ENTRIES;
+
+ cache_head.prev = &cache[dev->cache_entries-1];
+ cache_head.prev->next = &cache_head;
+ prev = &cache_head;
+
+ for (i = 0; i < dev->cache_entries; i++) {
+ cur = &cache[i];
+ cur->block = 0;
+ cur->prev = prev;
+ prev->next = cur;
+ cur->data = data;
+ data += dev->cache_block_size;
+ prev = cur++;
+ }
+}
+
+
+/*
+ * Check for a particular BLOCK in the block cache,
+ * and if it is already there, just do nothing and return;
+ * otherwise load it from disk and updata the LRU link.
+ *
+ */
+struct cache_struct* get_cache_block(struct device *dev, block_t block)
+{
+ struct cache_struct *head = (struct cache_struct *)dev->cache_head;
+ struct cache_struct *last = head->prev;
+ /* let's find it from the end, 'cause the endest is the freshest */
+ struct cache_struct *cs = head->prev;
+ int i;
+ static int total_read;
+ static int missed;
+
+#if 0
+ printf("we are looking for cache of %d\n", block);
+#endif
+
+ if (!block) {
+ printf("ERROR: we got a ZERO block number that's not we want!\n");
+ return NULL;
+ }
+
+ /* it's aleardy the freshest, so nothing we need do , just return it */
+ if (cs->block == block)
+ goto out;
+
+ for (i = 0; i < dev->cache_entries; i ++) {
+ if (cs->block == block)
+ break;
+ else
+ cs = cs->prev;
+ }
+
+ /* missed, so we need to load it */
+ if (i == dev->cache_entries) {
+ /* store it at the head of real cache */
+ cs = head->next;
+ cs->block = block;
+ getoneblk(dev->disk, cs->data, block, dev->cache_block_size);
+
+ missed ++;
+ }
+
+ /* remove cs from current position in list */
+ cs->prev->next = cs->next;
+ cs->next->prev = cs->prev;
+
+ /* add to just before head node */
+ last->next = cs;
+ cs->prev = last;
+ head->prev = cs;
+ cs->next = head;
+
+ out:
+ total_read ++;
+#if 0 /* testing how efficiency the cache is */
+ if (total_read % 5 == 0)
+ printf("total_read %d\tmissed %d\n", total_read, missed);
+#endif
+
+ /* in fact, that would never be happened */
+ if ((char *)(cs->data) > (char*)0x100000)
+ printf("the buffer addres higher than 1M limit\n");
+
+ return cs;
+}
+
+
+/*
+ * Just print the sector, and according the LRU algorithm,
+ * Left most value is the most least secotr, and Right most
+ * value is the most Recent sector. I see it's a Left Right Used
+ * (LRU) algorithm; Just kidding:)
+ */
+void print_cache(struct device *dev)
+{
+ int i = 0;
+ struct cache_struct *cs = dev->cache_head;
+ for (; i < dev->cache_entries; i++) {
+ cs = cs->next;
+ printf("%d(%p)\n", cs->block, cs->data);
+ }
+
+ printf("\n");
+}
diff --git a/core/cache.inc b/core/cache.inc
index 59755576..3b24cf04 100644
--- a/core/cache.inc
+++ b/core/cache.inc
@@ -10,7 +10,7 @@
;
; -----------------------------------------------------------------------
- section .text
+ section .text16
struc cptr
.sector: resd 1 ; Sector number
@@ -103,7 +103,7 @@ getcachesector:
pop cx
ret
- section .bss
+ section .bss16
; Each CachePtr contains:
; - Block pointer
diff --git a/core/call16.c b/core/call16.c
new file mode 100644
index 00000000..86d70461
--- /dev/null
+++ b/core/call16.c
@@ -0,0 +1,27 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * 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
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * call16.c
+ *
+ * Simple wrapper to call 16-bit core functions from 32-bit code
+ */
+
+#include <stddef.h>
+#include "core.h"
+
+const com32sys_t zero_regs; /* Common all-zero register set */
+
+void call16(void (*func)(void), const com32sys_t *ireg, com32sys_t *oreg)
+{
+ core_farcall((size_t)func, ireg, oreg);
+}
diff --git a/core/callback.inc b/core/callback.inc
new file mode 100644
index 00000000..a33b5825
--- /dev/null
+++ b/core/callback.inc
@@ -0,0 +1,208 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 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
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; callback.inc
+;;
+;; Callbacks from 32-bit mode to 16-bit mode
+;;
+
+;
+; 16-bit intcall/farcall handling code
+;
+
+;
+; 32-bit support code
+;
+ bits 32
+ section .text
+
+;
+; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
+; containing the com32sys_t structure from <com32.h> as well as
+; the following entries (from low to high address):
+; - Target offset
+; - Target segment
+; - Return offset
+; - Return segment (== real mode cs == 0)
+; - Return flags
+;
+ global core_farcall
+core_farcall:
+ mov eax,[esp+1*4] ; CS:IP
+ jmp core_syscall
+
+ global core_intcall
+core_intcall:
+ movzx eax,byte [esp+1*4] ; INT number
+ mov eax,[eax*4] ; Get CS:IP from low memory
+
+core_syscall:
+ pushfd ; Save IF among other things...
+ push ebx
+ push ebp
+ push esi
+ push edi
+ push dword [CallbackSP]
+
+ cld
+
+ movzx edi,word [word RealModeSSSP]
+ movzx ebx,word [word RealModeSSSP+2]
+ sub edi,54 ; Allocate 54 bytes
+ mov [word RealModeSSSP],di
+ shl ebx,4
+ add edi,ebx ; Create linear address
+
+ mov esi,[esp+8*4] ; Source regs
+ xor ecx,ecx
+ mov cl,11 ; 44 bytes to copy
+ rep movsd
+
+ ; EAX is already set up to be CS:IP
+ stosd ; Save in stack frame
+ mov eax,.rm_return ; Return seg:offs
+ stosd ; Save in stack frame
+ mov eax,[edi-12] ; Return flags
+ and eax,0x200cd7 ; Mask (potentially) unsafe flags
+ mov [edi-12],eax ; Primary flags entry
+ stosw ; Return flags
+
+ mov bx,.rm
+ jmp enter_rm ; Go to real mode
+
+ bits 16
+ section .text16
+.rm:
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ mov [cs:CallbackSP],sp
+ retf ; Invoke routine
+
+.rm_return:
+ ; We clean up SP here because we don't know if the
+ ; routine returned with RET, RETF or IRET
+ mov sp,[cs:CallbackSP]
+ pushfd
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ mov ebx,.pm_return
+ jmp enter_pm
+
+ ; On return, the 44-byte return structure is on the
+ ; real-mode stack, plus the 10 additional bytes used
+ ; by the target address (see above.)
+ bits 32
+ section .text
+.pm_return:
+ movzx esi,word [word RealModeSSSP]
+ movzx eax,word [word RealModeSSSP+2]
+ mov edi,[esp+9*4] ; Dest regs
+ shl eax,4
+ add esi,eax ; Create linear address
+ and edi,edi ; NULL pointer?
+ jnz .do_copy
+.no_copy: mov edi,esi ; Do a dummy copy-to-self
+.do_copy: xor ecx,ecx
+ mov cl,11 ; 44 bytes
+ rep movsd ; Copy register block
+
+ add dword [word RealModeSSSP],54
+ ; Remove from stack
+
+ pop dword [CallbackSP]
+ pop edi
+ pop esi
+ pop ebp
+ pop ebx
+ popfd
+ ret ; Return to 32-bit program
+
+;
+; Cfarcall invocation. We copy the stack frame to the real-mode stack,
+; followed by the return CS:IP and the CS:IP of the target function.
+;
+ global core_cfarcall
+core_cfarcall:
+ pushfd ; Save IF among other things...
+ push ebx
+ push ebp
+ push esi
+ push edi
+ push dword [CallbackSP]
+
+ cld
+ mov ecx,[esp+9*4] ; Size of stack frame
+
+ movzx edi,word [word RealModeSSSP]
+ movzx ebx,word [word RealModeSSSP+2]
+ mov [word CallbackSP],di
+ sub edi,ecx ; Allocate space for stack frame
+ and edi,~3 ; Round
+ sub edi,4*2 ; Return pointer, return value
+ mov [word RealModeSSSP],di
+ shl ebx,4
+ add edi,ebx ; Create linear address
+
+ mov eax,[esp+7*4] ; CS:IP
+ stosd ; Save to stack frame
+ mov eax,.rm_return ; Return seg:off
+ stosd
+ mov esi,[esp+8*4] ; Stack frame
+ mov eax,ecx ; Copy the stack frame
+ shr ecx,2
+ rep movsd
+ mov ecx,eax
+ and ecx,3
+ rep movsb
+
+ mov bx,.rm
+ jmp enter_rm
+
+ bits 16
+ section .text16
+.rm:
+ retf
+.rm_return:
+ mov sp,[cs:CallbackSP]
+ mov esi,eax
+ mov ebx,.pm_return
+ jmp enter_pm
+
+ bits 32
+ section .text
+.pm_return:
+ mov eax,esi
+ ; EDX already set up to be the RM return value
+ pop dword [CallbackSP]
+ pop ebx
+ pop ebp
+ pop esi
+ pop edi
+ popfd
+ ret
+
+ bits 16
+ section .bss16
+ alignb 4
+CallbackSP resd 1 ; SP saved during callback
+
+ bits 16
+ section .text16
diff --git a/core/checksumiso.pl b/core/checksumiso.pl
deleted file mode 100755
index 9b8c3ee5..00000000
--- a/core/checksumiso.pl
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/usr/bin/perl
-#
-# Construct a checksum for isolinux*.bin, compatible
-# with an mkisofs boot-info-table
-#
-
-use bytes;
-use integer;
-
-($file) = @ARGV;
-
-open(FILE, '+<', $file) or die "$0: cannot open $file: $!\n";
-binmode FILE;
-
-@fstat = stat(FILE) or die "$0: stat $file: $!\n";
-if (!$fstat[7]) {
- die "$0: $file: cannot query length\n";
-}
-
-# Pad file to a multiple of 2048 bytes
-$frac = $fstat[7] % 2048;
-if ($frac) {
- seek(FILE,$fstat[7],0)
- or die "$0: $file: cannot seek to end\n";
- print FILE "\0" x (2048-$frac);
-}
-
-# Checksum the file post header
-if ( !seek(FILE,64,0) ) {
- die "$0: $file: cannot seek past header\n";
-}
-
-$csum = 0;
-$bytes = 64;
-while ( ($n = read(FILE, $dw, 4)) > 0 ) {
- $dw .= "\0\0\0\0"; # Pad to at least 32 bits
- ($v) = unpack("V", $dw);
- $csum = ($csum + $v) & 0xffffffff;
- $bytes += $n;
-}
-
-# Update header
-if ( !seek(FILE,16,0) ) {
- die "$0: $file: cannot seek to header\n";
-}
-
-print FILE pack("VV", $bytes, $csum);
-
-close(FILE);
-
-exit 0;
diff --git a/core/cleanup.inc b/core/cleanup.inc
index 063ed73e..300584c7 100644
--- a/core/cleanup.inc
+++ b/core/cleanup.inc
@@ -16,7 +16,7 @@
;; Some final tidying before jumping to a kernel or bootsector
;;
- section .text
+ section .text16
;
; cleanup_hardware:
;
@@ -49,6 +49,11 @@ cleanup_hardware:
int 10h
.no_vmware:
%endif
+
+ call comboot_cleanup_api
+
+ call timer_cleanup
+
popad
; If we enabled serial port interrupts, clean them up now
diff --git a/core/cmdline.inc b/core/cmdline.inc
index 642e5e14..8b84f48d 100644
--- a/core/cmdline.inc
+++ b/core/cmdline.inc
@@ -45,7 +45,7 @@ make_plain_cmdline:
; Actual IPAppend strings...
;
%if IS_PXELINUX
- section .data
+ section .data16
alignz 2
IPAppends dw IPOption
dw BOOTIFStr
@@ -60,7 +60,7 @@ numIPAppends equ 0
;
; Assumes DS == CS; pushes output to ES:DI
;
- section .text
+ section .text16
do_ip_append:
%ifndef DEPEND
diff --git a/core/com32.inc b/core/com32.inc
index 72327929..3fa2d31e 100644
--- a/core/com32.inc
+++ b/core/com32.inc
@@ -1,6 +1,7 @@
;; -----------------------------------------------------------------------
;;
-;; Copyright 1994-2008 H. Peter Anvin - All Rights Reserved
+;; Copyright 1994-2009 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
@@ -26,30 +27,9 @@
; "mov ax,0x4cff; int 0x21" in 16-bit mode. This will abort the
; program with an error if run in 16-bit mode.
;
+com32_entry equ free_high_memory
- ; We need to make this a proper section rather
- ; than using absolute numbers, in order to work
- ; around a bug in GNU ld 2.17, which is still in
- ; use as of this writing in the form of Debian
- ; 4.0 (etch).
- bits 32
- section .com32 exec write nobits align=16
-pm_idt equ 0x100000 ; Needs to be absolute...
- resb 4096
-pm_entry: ; Needs to not be...
-
- bits 16
- section .data
- alignz 2
-com32_pmidt:
- dw 8*256 ; Limit
- dd pm_idt ; Address
-
-com32_rmidt:
- dw 0ffffh ; Limit
- dd 0 ; Address
-
- section .text
+ section .text16
is_com32_image:
push si ; Save file handle
push eax ; Save file length
@@ -67,362 +47,84 @@ is_com32_image:
call comboot_setup_api ; Set up the COMBOOT-style API
- mov edi,pm_entry ; Load address
+ mov edi,com32_entry ; Load address
pop eax ; File length
pop si ; File handle
xor dx,dx ; No padding
mov bx,abort_check ; Don't print dots, but allow abort
call load_high
-com32_start:
- mov ebx,com32_call_start ; Where to go in PM
-
-com32_enter_pm:
- cli
- mov ax,cs
- mov ds,ax
- mov [RealModeSSSP],sp
- mov [RealModeSSSP+2],ss
- cld
- call a20_test
- jnz .a20ok
- call enable_a20
-
-.a20ok:
- mov byte [bcopy_gdt.TSS+5],89h ; Mark TSS unbusy
-
- lgdt [bcopy_gdt] ; We can use the same GDT just fine
- lidt [com32_pmidt] ; Set up the IDT
- mov eax,cr0
- or al,1
- mov cr0,eax ; Enter protected mode
- jmp PM_CS32:.in_pm
-
- bits 32
-.in_pm:
- xor eax,eax ; Available for future use...
- mov fs,eax
- mov gs,eax
- lldt ax
+ mov esi,com32_entry
+ mov edi,trackbuf
+ mov ecx,5
+ call bcopy
+ cmp dword [trackbuf],0xcd4cfeb8
+ jne not_com32r
+ cmp byte [trackbuf+4],0x21
+ jne not_com32r
- mov al,PM_DS32 ; Set up data segments
- mov es,eax
- mov ds,eax
- mov ss,eax
-
- mov al,PM_TSS ; Be nice to Intel's VT by
- ltr ax ; giving it a valid TR
-
- mov esp,[PMESP] ; Load protmode %esp if available
- jmp ebx ; Go to where we need to go
+com32_start:
+ ;
+ ; Point the stack to the end of (permitted) high memory
+ ;
+ mov eax,[HighMemRsvd]
+ xor ax,ax ; Align to a 64K boundary
+ mov [PMESP],eax
+ mov ebx,.pm ; Where to go in PM
+ jmp enter_pm
;
; This is invoked right before the actually starting the COM32
; progam, in 32-bit mode...
;
-com32_call_start:
- ;
- ; Point the stack to the end of (permitted) high memory
- ;
- mov esp,[word HighMemRsvd]
- xor sp,sp ; Align to a 64K boundary
-
- ;
- ; Set up the protmode IDT and the interrupt jump buffers
- ; We set these up in the system area at 0x100000,
- ; but we could also put them beyond the stack.
- ;
- mov edi,pm_idt
-
- ; Form an interrupt gate descriptor
- mov eax,0x00200000+((pm_idt+8*256)&0x0000ffff)
- mov ebx,0x0000ee00+((pm_idt+8*256)&0xffff0000)
- xor ecx,ecx
- inc ch ; ecx <- 256
-
- push ecx
-.make_idt:
- stosd
- add eax,8
- xchg eax,ebx
- stosd
- xchg eax,ebx
- loop .make_idt
-
- pop ecx
-
- ; Each entry in the interrupt jump buffer contains
- ; the following instructions:
- ;
- ; 00000000 60 pushad
- ; 00000001 B0xx mov al,<interrupt#>
- ; 00000003 E9xxxxxxxx jmp com32_handle_interrupt
-
- mov eax,0e900b060h
- mov ebx,com32_handle_interrupt-(pm_idt+8*256+8)
-
-.make_ijb:
- stosd
- sub [edi-2],cl ; Interrupt #
- xchg eax,ebx
- stosd
- sub eax,8
- xchg eax,ebx
- loop .make_ijb
-
- ; Now everything is set up for interrupts...
+ bits 32
+ section .text
+.pm:
+ ; Set up the calling stack frame
push dword [HighMemSize] ; Memory managed by Syslinux
- push dword com32_cfarcall ; Cfarcall entry point
- push dword com32_farcall ; Farcall entry point
+ push dword core_cfarcall ; Cfarcall entry point
+ push dword core_farcall ; Farcall entry point
push dword (1 << 16) ; 64K bounce buffer
push dword (xfer_buf_seg << 4) ; Bounce buffer address
- push dword com32_intcall ; Intcall entry point
+ push dword core_intcall ; Intcall entry point
push dword command_line ; Command line pointer
push dword 7 ; Argument count
sti ; Interrupts OK now
- call pm_entry ; Run the program...
+ call com32_entry ; Run the program...
; ... on return, fall through to com32_exit ...
-
com32_exit:
- mov bx,com32_done ; Return to command loop
-
-com32_enter_rm:
- cli
- cld
- mov [PMESP],esp ; Save exit %esp
- xor esp,esp ; Make sure the high bits are zero
- jmp PM_CS16:.in_pm16 ; Return to 16-bit mode first
+ mov bx,.rm
+ jmp enter_rm
bits 16
-.in_pm16:
- mov ax,PM_DS16 ; Real-mode-like segment
- mov es,ax
- mov ds,ax
- mov ss,ax
- mov fs,ax
- mov gs,ax
-
- lidt [com32_rmidt] ; Real-mode IDT (rm needs no GDT)
- mov eax,cr0
- and al,~1
- mov cr0,eax
- jmp 0:.in_rm
-
-.in_rm: ; Back in real mode
- mov ax,cs ; Set up sane segments
- mov ds,ax
- mov es,ax
- mov fs,ax
- mov gs,ax
- lss sp,[RealModeSSSP] ; Restore stack
- jmp bx ; Go to whereever we need to go...
-
-com32_done:
+ section .text16
+.rm:
+ mov dword [PMESP],__stack_end ; Stop use of COM32 stack
sti
jmp enter_command
-;
-; 16-bit support code
-;
- bits 16
-
-;
-; 16-bit interrupt-handling code
-;
-com32_int_rm:
- pushf ; Flags on stack
- push cs ; Return segment
- push word .cont ; Return address
- push dword edx ; Segment:offset of IVT entry
- retf ; Invoke IVT routine
-.cont: ; ... on resume ...
- mov ebx,com32_int_resume
- jmp com32_enter_pm ; Go back to PM
-
-;
-; 16-bit intcall/farcall handling code
-;
-com32_sys_rm:
- pop gs
- pop fs
- pop es
- pop ds
- popad
- popfd
- mov [cs:Com32SysSP],sp
- retf ; Invoke routine
-.return:
- ; We clean up SP here because we don't know if the
- ; routine returned with RET, RETF or IRET
- mov sp,[cs:Com32SysSP]
- pushfd
- pushad
- push ds
- push es
- push fs
- push gs
- mov ebx,com32_syscall.resume
- jmp com32_enter_pm
-
-;
-; 16-bit cfarcall handing code
-;
-com32_cfar_rm:
- retf
-.return:
- mov sp,[cs:Com32SysSP]
- mov [cs:RealModeEAX],eax
- mov ebx,com32_cfarcall.resume
- jmp com32_enter_pm
-
-;
-; 32-bit support code
-;
- bits 32
-
-;
-; This is invoked on getting an interrupt in protected mode. At
-; this point, we need to context-switch to real mode and invoke
-; the interrupt routine.
-;
-; When this gets invoked, the registers are saved on the stack and
-; AL contains the register number.
-;
-com32_handle_interrupt:
- movzx eax,al
- xor ebx,ebx ; Actually makes the code smaller
- mov edx,[ebx+eax*4] ; Get the segment:offset of the routine
- mov bx,com32_int_rm
- jmp com32_enter_rm ; Go to real mode
-
-com32_int_resume:
- popad
- iret
-
-;
-; Intcall/farcall invocation. We manifest a structure on the real-mode stack,
-; containing the com32sys_t structure from <com32.h> as well as
-; the following entries (from low to high address):
-; - Target offset
-; - Target segment
-; - Return offset
-; - Return segment (== real mode cs == 0)
-; - Return flags
-;
-com32_farcall:
- pushfd ; Save IF among other things...
- pushad ; We only need to save some, but...
-
- mov eax,[esp+10*4] ; CS:IP
- jmp com32_syscall
-
-
-com32_intcall:
- pushfd ; Save IF among other things...
- pushad ; We only need to save some, but...
-
- movzx eax,byte [esp+10*4] ; INT number
- mov eax,[eax*4] ; Get CS:IP from low memory
-
-com32_syscall:
- cld
-
- movzx edi,word [word RealModeSSSP]
- movzx ebx,word [word RealModeSSSP+2]
- sub edi,54 ; Allocate 54 bytes
- mov [word RealModeSSSP],di
- shl ebx,4
- add edi,ebx ; Create linear address
-
- mov esi,[esp+11*4] ; Source regs
- xor ecx,ecx
- mov cl,11 ; 44 bytes to copy
- rep movsd
-
- ; EAX is already set up to be CS:IP
- stosd ; Save in stack frame
- mov eax,com32_sys_rm.return ; Return seg:offs
- stosd ; Save in stack frame
- mov eax,[edi-12] ; Return flags
- and eax,0x200cd7 ; Mask (potentially) unsafe flags
- mov [edi-12],eax ; Primary flags entry
- stosw ; Return flags
-
- mov bx,com32_sys_rm
- jmp com32_enter_rm ; Go to real mode
-
- ; On return, the 44-byte return structure is on the
- ; real-mode stack, plus the 10 additional bytes used
- ; by the target address (see above.)
-.resume:
- movzx esi,word [word RealModeSSSP]
- movzx eax,word [word RealModeSSSP+2]
- mov edi,[esp+12*4] ; Dest regs
- shl eax,4
- add esi,eax ; Create linear address
- and edi,edi ; NULL pointer?
- jnz .do_copy
-.no_copy: mov edi,esi ; Do a dummy copy-to-self
-.do_copy: xor ecx,ecx
- mov cl,11 ; 44 bytes
- rep movsd ; Copy register block
-
- add dword [word RealModeSSSP],54 ; Remove from stack
-
- popad
- popfd
- ret ; Return to 32-bit program
-
-;
-; Cfarcall invocation. We copy the stack frame to the real-mode stack,
-; followed by the return CS:IP and the CS:IP of the target function.
-;
-com32_cfarcall:
- pushfd
- pushad
-
- cld
- mov ecx,[esp+12*4] ; Size of stack frame
-
- movzx edi,word [word RealModeSSSP]
- movzx ebx,word [word RealModeSSSP+2]
- mov [word Com32SysSP],di
- sub edi,ecx ; Allocate space for stack frame
- and edi,~3 ; Round
- sub edi,4*2 ; Return pointer, return value
- mov [word RealModeSSSP],di
- shl ebx,4
- add edi,ebx ; Create linear address
-
- mov eax,[esp+10*4] ; CS:IP
- stosd ; Save to stack frame
- mov eax,com32_cfar_rm.return ; Return seg:off
- stosd
- mov esi,[esp+11*4] ; Stack frame
- mov eax,ecx ; Copy the stack frame
- shr ecx,2
- rep movsd
- mov ecx,eax
- and ecx,3
- rep movsb
-
- mov bx,com32_cfar_rm
- jmp com32_enter_rm
-
-.resume:
- popad
- mov eax,[word RealModeEAX]
- popfd
- ret
-
- bits 16
-
- section .bss1
- alignb 4
-RealModeSSSP resd 1 ; Real-mode SS:SP
-RealModeEAX resd 1 ; Real mode EAX
-PMESP resd 1 ; Protected-mode ESP
-Com32SysSP resw 1 ; SP saved during COM32 syscall
+not_com32r:
+ mov si,KernelCName
+ call writestr
+ mov si,not_com32r_msg
+ call writestr
+ jmp enter_command
- section .text
+ section .data16
+not_com32r_msg db ': not a COM32R image', CR, LF, 0
+
+ ; Ersatz com32 invocation structure, to make libcom32
+ ; code run the same if linked to the core. This is in
+ ; the .data16 segment so HighMemSize can live here.
+ global __com32
+ alignz 4
+__com32:
+ dd 7 ; Argument count
+ dd 0 ; No command line
+ dd core_intcall ; Intcall entry point
+ dd core_xfer_buf ; Bounce buffer address
+ dd 1 << 16 ; 64K bounce buffer
+ dd core_farcall ; Farcall entry point
+ dd core_cfarcall ; Cfarcall entry point
+HighMemSize dd 0 ; End of memory pointer (bytes)
diff --git a/core/comboot.inc b/core/comboot.inc
index cdba16d5..25409595 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -17,7 +17,7 @@
;; Common code for running a COMBOOT image
;;
- section .text
+ section .text16
; Parameter registers definition; this is the definition
; of the stack frame used by INT 21h and INT 22h.
@@ -63,7 +63,7 @@
; Looks like a COMBOOT image but too large
comboot_too_large:
- call close_file
+ pm_call close_file
mov si,err_comlarge
call writestr
jmp enter_command
@@ -126,7 +126,7 @@ is_comboot_image:
mov bx,100h ; Load at <seg>:0100h
mov cx,10000h >> SECTOR_SHIFT
; Absolute maximum # of sectors
- call getfssec
+ pm_call getfssec
cmp ecx,65536-256-2 ; Maximum size
ja comboot_too_large
@@ -148,8 +148,8 @@ comboot_return: cli ; May not have a safe stack
jmp comboot_exit
;
-; Set up the COMBOOT API interrupt vectors. This is also used
-; by the COM32 code.
+; Set up the COMBOOT API interrupt vectors. This is now done at
+; initialization time.
;
comboot_setup_api:
mov di,DOSErrTramp ; Error trampolines
@@ -178,11 +178,23 @@ comboot_setup_api:
loop .loop2
ret
- section .bss
+;
+; Restore the original state of the COMBOOT API vectors
+;
+comboot_cleanup_api:
+ pusha
+ mov si,DOSSaveVectors
+ mov di,4*20h
+ mov cx,20h
+ rep movsd ; Restore DOS-range vectors
+ popa
+ ret
+
+ section .bss16
alignb 4
DOSSaveVectors resd 32
- section .data
+ section .data16
%define comboot_err(x) (DOSErrTramp+4*((x)-20h))
comboot_vectors:
@@ -219,7 +231,7 @@ comboot_vectors:
dw comboot_err(3Eh) ; INT 3E = DOS FPU emulation
dw comboot_err(3Fh) ; INT 3F = DOS overlay manager
- section .text
+ section .text16
; INT 21h: generic DOS system call
comboot_int21: sti
@@ -295,12 +307,6 @@ comboot_exit_msg:
pop bx ; Return address
RESET_STACK_AND_SEGS SI ; Contains sti, cld
call adjust_screen ; The COMBOOT program might have changed the screen
- pusha
- mov si,DOSSaveVectors
- mov di,4*20h
- mov cx,20h
- rep movsd ; Restore DOS-range vectors
- popa
jcxz .nomsg
mov si,KernelCName
call writestr
@@ -511,9 +517,9 @@ comapi_open:
mov ds,P_ES
mov si,P_SI
mov di,InitRD
- call mangle_name
+ pm_call mangle_name
pop ds
- call searchdir
+ pm_call searchdir
jz comapi_err
mov P_EAX,eax
mov P_CX,SECTOR_SIZE
@@ -529,7 +535,7 @@ comapi_read:
mov bx,P_BX
mov si,P_SI
mov cx,P_CX
- call getfssec
+ pm_call getfssec
jnc .noteof
xor si,si ; SI <- 0 on EOF, CF <- 0
.noteof: mov P_SI,si
@@ -541,7 +547,7 @@ comapi_read:
;
comapi_close:
mov si,P_SI
- call close_file
+ pm_call close_file
clc
ret
@@ -629,7 +635,7 @@ comapi_cleanup:
test dl,3
setnz [KeepPXE]
sub bp,sp ; unload_pxe may move the stack around
- call unload_pxe
+ pm_call unload_pxe
add bp,sp ; restore frame pointer...
%elif IS_SYSLINUX || IS_EXTLINUX
; Restore original FDC table
@@ -680,10 +686,11 @@ comapi_ipappend:
; INT 22h AX=0010h Resolve hostname
;
%if IS_PXELINUX
+ extern pxe_dns_resolv
comapi_dnsresolv:
mov ds,P_ES
mov si,P_BX
- call dns_resolv
+ pm_call pxe_dns_resolv
mov P_EAX,eax
clc
ret
@@ -691,7 +698,7 @@ comapi_dnsresolv:
comapi_dnsresolv equ comapi_err
%endif
- section .text
+ section .text16
;
; INT 22h AX=0011h Obsolete
@@ -742,9 +749,9 @@ comapi_runkernel:
mov ds,P_DS
mov si,P_SI
mov di,KernelName
- call mangle_name
+ pm_call mangle_name
pop ds
- call searchdir
+ pm_call searchdir
jz comapi_err
; The kernel image was found, so we can load it...
@@ -892,59 +899,44 @@ comapi_getcwd:
;
; INT 22h AX=0020h Open directory
;
-%if IS_SYSLINUX
+%if IS_PXELINUX
+comapi_opendir equ comapi_err
+
+%else
comapi_opendir:
- push ds
- mov ds,P_ES
+ mov es,P_ES
mov si,P_SI
mov di,InitRD
- call mangle_name
- pop ds
- call searchdir
- jnz comapi_err ; Didn't find a directory
+ pm_call opendir
+ jz comapi_err ; Didn't find a directory
cmp eax,0
jz comapi_err ; Found nothing
- ;ZF is unset
- call alloc_fill_dir
- mov P_EAX,eax
- mov P_CX,SECTOR_SIZE
- mov P_SI,si
+ mov P_EAX,eax
clc
ret
-%else
-comapi_opendir equ comapi_err
%endif
;
; INT 22h AX=0021h Read directory
;
-%if IS_SYSLINUX
+%if IS_PXELINUX
+comapi_readdir equ comapi_err
+
+%else
comapi_readdir:
- mov es,P_ES
- mov di,P_DI
- mov si,P_SI
- call readdir
- mov P_EAX,eax
- mov P_DL,dl
- mov P_EBX,ebx
- mov P_SI,si
+ mov esi,P_ESI ; The address of DIR structure
+ pm_call readdir
+ mov P_EAX,eax ; The address of newly read dirent structure
ret
-%else
-comapi_readdir equ comapi_err
%endif
;
; INT 22h AX=0022h Close directory
;
-%if IS_SYSLINUX
comapi_closedir:
- mov si,P_SI
- call close_dir
- clc
+ mov esi,P_ESI ; The address of DIR structure
+ pm_call closedir
ret
-%else
-comapi_closedir equ comapi_err
-%endif
;
; INT 22h AX=0023h Query shuffler size
@@ -963,7 +955,7 @@ comapi_shufraw:
mov ecx,P_ECX
jmp shuffle_and_boot_raw
- section .data
+ section .data16
%macro int21 2
db %1
@@ -1042,8 +1034,10 @@ feature_flags_len equ ($-feature_flags)
err_notdos db ': attempted DOS system call INT ',0
err_comlarge db 'COMBOOT image too large.', CR, LF, 0
- section .bss1
+ section .bss16
alignb 4
DOSErrTramp resd 33 ; Error trampolines
+
+ global ConfigName, CurrentDirName
ConfigName resb FILENAME_MAX
CurrentDirName resb FILENAME_MAX
diff --git a/core/common.inc b/core/common.inc
new file mode 100644
index 00000000..7078011e
--- /dev/null
+++ b/core/common.inc
@@ -0,0 +1,25 @@
+;
+; Modules common to all derivatives. Do not include modules in this list
+; which have special section requirements (i.e. need to be in .init for
+; some derivatives.)
+;
+
+%include "getc.inc" ; getc et al
+%include "conio.inc" ; Console I/O
+%include "configinit.inc" ; Initialize configuration
+%include "parseconfig.inc" ; High-level config file handling
+%include "parsecmd.inc" ; Low-level config file handling
+%include "pm.inc" ; Protected mode
+%include "bcopy32.inc" ; 32-bit bcopy
+%include "loadhigh.inc" ; Load a file into high memory
+%include "font.inc" ; VGA font stuff
+%include "graphics.inc" ; VGA graphics
+%include "highmem.inc" ; High memory sizing
+%include "strcpy.inc" ; strcpy()
+%include "idle.inc" ; Idle handling
+%include "adv.inc" ; Auxillary Data Vector
+%include "timer.inc" ; Timer handling
+
+; Note: the prefix section is included late, to avoid problems with some
+; versions of NASM that had issues with forward references to EQU symbols.
+%include "prefix.inc" ; Prefix section for prepcore
diff --git a/core/config.inc b/core/config.inc
index 5a3d1c5a..269e13ec 100644
--- a/core/config.inc
+++ b/core/config.inc
@@ -32,6 +32,12 @@ MAX_FKEYS equ 12 ; Number of F-key help files
%assign HAS_LOCALBOOT 1
;
+; log2(Max filename size Including final null)
+;
+FILENAME_MAX_LG2 equ 8
+FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size
+
+;
; Version number definitinons
;
%include "../version.gen"
diff --git a/core/configinit.inc b/core/configinit.inc
index cf6a814c..1dd253ce 100644
--- a/core/configinit.inc
+++ b/core/configinit.inc
@@ -16,7 +16,7 @@
;; Initialize the configuration section
;;
- section .text
+ section .text16
reset_config:
call highmemsize
@@ -54,6 +54,6 @@ mkkeymap: stosb
ret
- section .data
+ section .data16
linuxauto_cmd db 'linux auto',0
linuxauto_len equ $-linuxauto_cmd
diff --git a/core/conio.inc b/core/conio.inc
index 16c39c65..835359fb 100644
--- a/core/conio.inc
+++ b/core/conio.inc
@@ -24,7 +24,7 @@
; loadkeys: Load a LILO-style keymap; file is open on the top of the
; getc stack.
;
- section .text
+ section .text16
loadkeys:
mov cx,256
@@ -207,8 +207,8 @@ msg_viewimage:
mov byte [si],0 ; Zero-terminate filename
mov si,VGAFileBuf
mov di,VGAFileMBuf
- call mangle_name
- call open
+ pm_call mangle_name
+ call core_open
jz msg_putcharnext ; Not there
call vgadisplayfile
; Fall through
@@ -389,7 +389,7 @@ debug_tracer: pushad
ret
%endif ; DEBUG_TRACERS
- section .data
+ section .data16
%if IS_ISOLINUX == 0 ; Defined elsewhere for ISOLINUX
crlf_msg db CR, LF
null_msg db 0
@@ -402,7 +402,7 @@ DisplayCon dw 01h ; Console display enabled
ScrollAttribute db 07h ; Grey on white (normal text color)
- section .bss
+ section .bss16
alignb 2
NextCharJump resw 1 ; Routine to interpret next print char
CursorDX equ $
@@ -414,7 +414,7 @@ VidRows resb 1 ; Rows on screen-1
; Serial console stuff; don't put this in .config becasue we don't want
; loading a new config file to undo this setting.
- section .data
+ section .data16
alignz 4
SerialPort dw 0 ; Serial port base (or 0 for no serial port)
BaudDivisor dw 115200/9600 ; Baud rate divisor
@@ -424,8 +424,9 @@ FlowInput db 0 ; Input bits for serial flow
FlowIgnore db 0 ; Ignore input unless these bits set
FlowDummy db 0 ; Unused
- section .bss
+ section .bss16
TextAttribute resb 1 ; Text attribute for message file
DisplayMask resb 1 ; Display modes mask
+ section .text16
%include "serirq.inc"
diff --git a/core/cpuinit.inc b/core/cpuinit.inc
deleted file mode 100644
index 4d8cc2e7..00000000
--- a/core/cpuinit.inc
+++ /dev/null
@@ -1,52 +0,0 @@
-;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-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.
-;;
-;; -----------------------------------------------------------------------
-
-;;
-;; cpuinit.inc
-;;
-;; CPU-dependent initialization and related checks.
-;;
-
-check_escapes:
- mov ah,02h ; Check keyboard flags
- int 16h
- mov [KbdFlags],al ; Save for boot prompt check
- test al,04h ; Ctrl->skip 386 check
- jnz skip_checks
-
-;
-; Now check that there is sufficient low (DOS) memory
-;
-; NOTE: Linux doesn't use all of real_mode_seg, but we use the same
-; segment for COMBOOT images, which can use all 64K
-;
-dosram_k equ (real_mode_seg+0x1000) >> 6 ; Minimum DOS memory (K)
- int 12h
- cmp ax,dosram_k
- jae enough_ram
- mov si,err_noram
- call writestr_early
- jmp kaboom
-enough_ram:
-skip_checks:
-
- section .data
-err_noram db 'It appears your computer has less than '
- asciidec dosram_k
- db 'K of low ("DOS")'
- db CR, LF
- db 'RAM. Linux needs at least this amount to boot. If you get'
- db CR, LF
- db 'this message in error, hold down the Ctrl key while'
- db CR, LF
- db 'booting, and I will take your word for it.', CR, LF, 0
- section .text
diff --git a/core/dir.c b/core/dir.c
new file mode 100644
index 00000000..37d92ed2
--- /dev/null
+++ b/core/dir.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <fs.h>
+#include <core.h>
+
+extern struct fs_info *this_fs;
+
+/*
+ * open dir, return the file structure pointer in _eax_, or NULL if failed
+ */
+void opendir(com32sys_t *regs)
+{
+ char *src = MK_PTR(regs->es, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->ds, regs->edi.w[0]);
+ strcpy(dst, src);
+ searchdir(regs);
+ regs->eax.l = (uint32_t)handle_to_file(regs->esi.w[0]);
+}
+
+/*
+ * Read one dirent at one time.
+ *
+ * @input: _esi_ register stores the address of DIR structure
+ * @output: _eax_ register stores the address of newly read dirent structure
+ */
+void readdir(com32sys_t *regs)
+{
+ DIR *dir = (DIR *)regs->esi.l;
+ struct dirent *de = NULL;
+
+ if (dir->dd_dir)
+ de = this_fs->fs_ops->readdir(dir->dd_dir);
+ else
+ de = NULL;
+
+ /* Return the newly read de in _eax_ register */
+ regs->eax.l = (uint32_t)de;
+}
+
+void closedir(com32sys_t *regs)
+{
+ DIR *dir = (DIR *)regs->esi.l;
+ _close_file(dir->dd_dir);
+}
+
+
diff --git a/core/diskfs.inc b/core/diskfs.inc
new file mode 100644
index 00000000..b8d03762
--- /dev/null
+++ b/core/diskfs.inc
@@ -0,0 +1,182 @@
+; -*- fundamental -*- (asm-mode sucks)
+; -----------------------------------------------------------------------
+;
+; Copyright 1994-2009 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
+; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+; Boston MA 02110-1301, USA; either version 2 of the License, or
+; (at your option) any later version; incorporated herein by reference.
+;
+; -----------------------------------------------------------------------
+
+;
+; diskfs.inc
+;
+; Common code for conventional disk-based filesystems
+;
+
+;
+; Some semi-configurable constants... change on your own risk.
+;
+NULLFILE equ 0 ; Null character == empty filename
+NULLOFFSET equ 0 ; Position in which to look
+retry_count equ 16 ; How patient are we with the disk?
+%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
+LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
+
+SECTOR_SHIFT equ 9
+SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+
+;
+; The following structure is used for "virtual kernels"; i.e. LILO-style
+; option labels. The options we permit here are `kernel' and `append
+; Since there is no room in the bottom 64K for all of these, we
+; stick them in high memory and copy them down before we need them.
+;
+ struc vkernel
+vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
+vk_rname: resb FILENAME_MAX ; Real name
+vk_appendlen: resw 1
+vk_type: resb 1 ; Type of file
+ alignb 4
+vk_append: resb max_cmd_len+1 ; Command line
+ alignb 4
+vk_end: equ $ ; Should be <= vk_size
+ endstruc
+
+
+
+; ---------------------------------------------------------------------------
+; BEGIN CODE
+; ---------------------------------------------------------------------------
+
+;
+; Memory below this point is reserved for the BIOS and the MBR
+;
+ section .earlybss
+ global trackbuf
+trackbufsize equ 8192
+trackbuf resb trackbufsize ; Track buffer goes here
+ ; ends at 2800h
+
+;
+; Common bootstrap code for disk-based derivatives
+;
+%include "diskstart.inc"
+
+
+;
+; Now, everything is "up and running"... patch kaboom for more
+; verbosity and using the full screen system
+;
+ ; E9 = JMP NEAR
+ mov di,kaboom.patch
+ mov al,0e9h
+ stosb
+ mov ax,kaboom2-2
+ sub ax,di
+ stosw
+
+;
+; Now we're all set to start with our *real* business. First load the
+; configuration file (if any) and parse it.
+;
+; In previous versions I avoided using 32-bit registers because of a
+; rumour some BIOSes clobbered the upper half of 32-bit registers at
+; random. I figure, though, that if there are any of those still left
+; they probably won't be trying to install Linux on them...
+;
+; The code is still ripe with 16-bitisms, though. Not worth the hassle
+; to take'm out. In fact, we may want to put them back if we're going
+; to boot ELKS at some point.
+;
+
+;
+; Load configuration file
+;
+ pm_call load_config
+ jz no_config_file
+
+;
+; Now we have the config file open. Parse the config file and
+; run the user interface.
+;
+%include "ui.inc"
+
+;
+;
+; kaboom2: once everything is loaded, replace the part of kaboom
+; starting with "kaboom.patch" with this part
+
+kaboom2:
+ mov si,err_bootfailed
+ call writestr
+ cmp byte [kaboom.again+1],18h ; INT 18h version?
+ je .int18
+ call getchar
+ call vgaclearmode
+ int 19h ; And try once more to boot...
+.norge: jmp short .norge ; If int 19h returned; this is the end
+.int18:
+ call vgaclearmode
+ int 18h
+.noreg: jmp short .noreg ; Nynorsk
+
+; -----------------------------------------------------------------------------
+; Common modules
+; -----------------------------------------------------------------------------
+
+%include "common.inc" ; Universal modules
+%include "plaincon.inc" ; writechr
+%include "writestr.inc" ; String output
+%include "writehex.inc" ; Hexadecimal output
+%include "localboot.inc" ; Disk-based local boot
+
+; -----------------------------------------------------------------------------
+; Begin data section
+; -----------------------------------------------------------------------------
+
+ section .data16
+copyright_str db ' Copyright (C) 1994-'
+ asciidec YEAR
+ db ' H. Peter Anvin et al', CR, LF, 0
+err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
+ db 'a key to continue.', CR, LF, 0
+
+;
+; Config file keyword table
+;
+%include "keywords.inc"
+
+;
+; Extensions to search for (in *forward* order).
+;
+ alignz 4
+exten_table: db '.cbt' ; COMBOOT (specific)
+%if IS_SYSLINUX
+ db '.bss' ; Boot sector (add superblock)
+%endif
+ db '.bs', 0 ; Boot sector
+ db '.com' ; COMBOOT (same as DOS)
+ db '.c32' ; COM32
+exten_table_end:
+ dd 0, 0 ; Need 8 null bytes here
+
+;
+; Misc initialized (data) variables
+;
+%ifdef debug ; This code for debugging only
+debug_magic dw 0D00Dh ; Debug code sentinel
+%endif
+
+ alignz 4
+BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
+BufSafeBytes dw trackbufsize ; = how many bytes?
+%ifndef DEPEND
+%if ( trackbufsize % SECTOR_SIZE ) != 0
+%error trackbufsize must be a multiple of SECTOR_SIZE
+%endif
+%endif
diff --git a/core/diskio.c b/core/diskio.c
new file mode 100644
index 00000000..911e4ddf
--- /dev/null
+++ b/core/diskio.c
@@ -0,0 +1,312 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+#include <klibc/compiler.h>
+#include <core.h>
+#include <fs.h>
+#include <disk.h>
+
+#define RETRY_COUNT 6
+
+static uint16_t MaxTransfer = 1 << (16 - 9);
+
+static int chs_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ uint32_t xlba = lba + disk->part_start; /* Truncated LBA (CHS is << 2 TB) */
+ uint32_t t;
+ uint16_t c, h, s;
+ com32sys_t ireg, oreg;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x02 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+
+ while (count) {
+ chunk = count;
+ if (chunk > MaxTransfer)
+ chunk = MaxTransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)buf <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ s = xlba % disk->s;
+ t = xlba / disk->s;
+ h = t % disk->h;
+ c = t / disk->h;
+
+ ireg.eax.b[0] = chunk;
+ ireg.ecx.b[1] = c;
+ ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1);
+ ireg.edx.b[1] = h;
+ ireg.ebx.w[0] = OFFS(tptr);
+ ireg.es = SEG(tptr);
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+ if (retry--)
+ continue;
+
+ /* if we are reading ONE sector and go here, just make it _faile_ */
+ chunk = chunk == 1 ? 0 : ((chunk+1) >> 1);
+ if (chunk) {
+ MaxTransfer = chunk;
+ retry = RETRY_COUNT;
+ ireg.eax.b[0] = chunk;
+ continue;
+ }
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ ptr += bytes;
+ xlba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+
+ return done;
+}
+
+struct edd_rdwr_packet {
+ uint16_t size;
+ uint16_t blocks;
+ far_ptr_t buf;
+ uint64_t lba;
+};
+
+static int edd_rdwr_sectors(struct disk *disk, void *buf,
+ sector_t lba, size_t count, bool is_write)
+{
+ static __lowmem struct edd_rdwr_packet pkt;
+ char *ptr = buf;
+ char *tptr;
+ size_t chunk, freeseg;
+ int sector_shift = disk->sector_shift;
+ com32sys_t ireg, oreg;
+ size_t done = 0;
+ size_t bytes;
+ int retry;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ ireg.eax.b[1] = 0x42 + is_write;
+ ireg.edx.b[0] = disk->disk_number;
+ ireg.ds = SEG(&pkt);
+ ireg.esi.w[0] = OFFS(&pkt);
+
+ lba += disk->part_start;
+ while (count) {
+ chunk = count;
+ if (chunk > MaxTransfer)
+ chunk = MaxTransfer;
+
+ freeseg = (0x10000 - ((size_t)ptr & 0xffff)) >> sector_shift;
+
+ if ((size_t)buf <= 0xf0000 && freeseg) {
+ /* Can do a direct load */
+ tptr = ptr;
+ } else {
+ /* Either accessing high memory or we're crossing a 64K line */
+ tptr = core_xfer_buf;
+ freeseg = (0x10000 - ((size_t)tptr & 0xffff)) >> sector_shift;
+ }
+ if (chunk > freeseg)
+ chunk = freeseg;
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && is_write)
+ memcpy(tptr, ptr, bytes);
+
+ pkt.size = sizeof pkt;
+ pkt.blocks = chunk;
+ pkt.buf = FAR_PTR(tptr);
+ pkt.lba = lba;
+
+ retry = RETRY_COUNT;
+
+ for (;;) {
+ __intcall(0x13, &ireg, &oreg);
+ if (!(oreg.eflags.l & EFLAGS_CF))
+ break;
+ if (retry--)
+ continue;
+ chunk = chunk == 1 ? 0 : ((chunk+1) >> 1);
+ if (chunk) {
+ MaxTransfer = chunk;
+ retry = RETRY_COUNT;
+ pkt.blocks = chunk;
+ continue;
+ }
+ /*** XXX: Consider falling back to CHS here?! ***/
+ printf("reading sectors error(EDD)\n");
+ return done; /* Failure */
+ }
+
+ bytes = chunk << sector_shift;
+
+ if (tptr != ptr && !is_write)
+ memcpy(ptr, tptr, bytes);
+
+ ptr += bytes;
+ lba += chunk;
+ count -= chunk;
+ done += chunk;
+ }
+ return done;
+}
+struct edd_disk_params {
+ uint16_t len;
+ uint16_t flags;
+ uint32_t phys_c;
+ uint32_t phys_h;
+ uint32_t phys_s;
+ uint64_t sectors;
+ uint16_t sector_size;
+ far_ptr_t dpte;
+ uint16_t devpath_key;
+ uint8_t devpath_len;
+ uint8_t _pad1[3];
+ char bus_type[4];
+ char if_type[8];
+ uint8_t if_path[8];
+ uint8_t dev_path[8];
+ uint8_t _pad2;
+ uint8_t devpath_csum;
+} __attribute__((packed));
+
+static inline bool is_power_of_2(uint32_t x)
+{
+ return !(x & (x-1));
+}
+
+static int ilog2(uint32_t num)
+{
+ int i = 0;
+
+ if (!is_power_of_2(num)) {
+ printf("ERROR: the num must be power of 2 when conveting to log2\n");
+ return 0;
+ }
+ while (num >>= 1)
+ i++;
+ return i;
+}
+
+void getoneblk(struct disk *disk, char *buf, block_t block, int block_size)
+{
+ int sec_per_block = block_size / disk->sector_size;
+
+ disk->rdwr_sectors(disk, buf, block * sec_per_block, sec_per_block, 0);
+}
+
+
+struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start,
+ uint16_t bsHeads, uint16_t bsSecPerTrack)
+{
+ static struct disk disk;
+ static __lowmem struct edd_disk_params edd_params;
+ com32sys_t ireg, oreg;
+ bool ebios = cdrom;
+ int sector_size = cdrom ? 2048 : 512;
+
+ memset(&ireg, 0, sizeof ireg);
+
+ /* Get EBIOS support */
+ ireg.eax.b[1] = 0x41;
+ ireg.ebx.w[0] = 0x55aa;
+ ireg.edx.b[0] = devno;
+ ireg.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &ireg, &oreg);
+
+ if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) &&
+ oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) {
+ /* Query EBIOS parameters */
+ ireg.eax.b[1] = 0x48;
+ ireg.ds = SEG(&edd_params);
+ ireg.esi.w[0] = OFFS(&edd_params);
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) {
+ ebios = true;
+ if (edd_params.sector_size >= 512 &&
+ is_power_of_2(edd_params.sector_size))
+ sector_size = edd_params.sector_size;
+ }
+ }
+
+ /* CBIOS parameters */
+ disk.h = bsHeads;
+ disk.s = bsSecPerTrack;
+
+ if ((int8_t)devno < 0) {
+ /* Get hard disk geometry from BIOS */
+
+ ireg.eax.b[1] = 0x08;
+ __intcall(0x13, &ireg, &oreg);
+
+ if (!(oreg.eflags.l & EFLAGS_CF)) {
+ disk.h = oreg.edx.b[1] + 1;
+ disk.s = oreg.ecx.b[0] & 63;
+ }
+ }
+
+ disk.disk_number = devno;
+ disk.type = ebios;
+ disk.sector_size = sector_size;
+ disk.sector_shift = ilog2(sector_size);
+ disk.part_start = part_start;
+ disk.rdwr_sectors = ebios ? edd_rdwr_sectors : chs_rdwr_sectors;
+
+ return &disk;
+}
+
+
+/*
+ * initialize the device structure
+ */
+struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start,
+ uint16_t bsHeads, uint16_t bsSecPerTrack)
+{
+ static struct device dev;
+
+ dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack);
+
+ dev.cache_data = core_cache_buf;
+ dev.cache_size = sizeof core_cache_buf;
+
+ return &dev;
+}
diff --git a/core/diskstart.inc b/core/diskstart.inc
index 53229223..8bb4f78a 100644
--- a/core/diskstart.inc
+++ b/core/diskstart.inc
@@ -18,11 +18,12 @@
;
; Expanded superblock
- section .bss
+ section .earlybss
alignb 8
SuperInfo resq 16 ; The first 16 bytes expanded 8 times
+DriveNumber resb 1
- section .text
+ section .init
;
; Some of the things that have to be saved very early are saved
; "close" to the initial stack pointer offset, in order to
@@ -33,6 +34,7 @@ PartInfo equ StackBuf ; Saved partition table entry
FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
OrigFDCTabPtr equ StackBuf-8 ; The 2nd high dword on the stack
OrigESDI equ StackBuf-4 ; The high dword on the stack
+StackTop equ OrigFDCTabPtr ; The start of the canonical stack
;
; Primary entry point. Tempting as though it may be, we can't put the
@@ -94,6 +96,7 @@ superblock_len_fat32 equ $-superblock+54
zb 54 ; Maximum needed size
superblock_max equ $-superblock
+ global SecPerClust
SecPerClust equ bxSecPerClust
;
; Note we don't check the constraints above now; we did that at install
@@ -250,6 +253,7 @@ getonesec:
; that is dead from that point; this saves space. However, please keep
; the order to dst,src to keep things sane.
;
+ global getlinsec
getlinsec:
add eax,[bsHidden] ; Add partition offset
xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
@@ -407,11 +411,12 @@ getlinsec_cbios:
;
; kaboom: write a message and bail out.
;
+ global kaboom
disk_error:
kaboom:
xor si,si
mov ss,si
- mov sp,StackBuf-4 ; Reset stack
+ mov sp,OrigFDCTabPtr ; Reset stack
mov ds,si ; Reset data segment
pop dword [fdctab] ; Restore FDC table
.patch: ; When we have full code, intercept here
@@ -451,6 +456,7 @@ bailmsg: db 'Boot error', 0Dh, 0Ah, 0
zb 1F8h-($-$$)
FirstSector dd 0xDEADBEEF ; Location of sector 1
+ global MaxTransfer
MaxTransfer dw 0x007F ; Max transfer size
; This field will be filled in 0xAA55 by the installer, but we abuse it
@@ -480,18 +486,15 @@ 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
+ global CurrentDir
+CurrentDir dd 2 ; "Current" directory inode number (EXTLINUX)
+SecPtrOffset dw SectorPtrs - ldlinux_sys
+SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2
ldlinux_ent:
;
@@ -523,23 +526,25 @@ print_bios:
mov [BIOSName],si
call writestr_early
- section .bss
+ section .earlybss
%define HAVE_BIOSNAME 1
BIOSName resw 1
- section .text
+ section .init
;
; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
; 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
+ mov di,bx ; Low 64K of target address
lodsd ; First sector of this chunk
mov edx,eax
@@ -548,16 +553,27 @@ 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
add si,4 ; If so, add sector to chunk
- jmp short .make_chunk
+ add di,SECTOR_SIZE ; Check for 64K segment wrap
+ jnz .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:
@@ -569,14 +585,23 @@ load_rest:
;
verify_checksum:
mov si,ldlinux_sys
- mov cx,[LDLDwords]
- mov edx,-LDLINUX_MAGIC
+ mov ecx,[LDLDwords]
+ mov eax,-LDLINUX_MAGIC
+ push ds
.checksum:
- lodsd
- add edx,eax
- loop .checksum
+ add eax,[si]
+ add si,4
+ jnz .nowrap
+ ; Handle segment wrap
+ mov dx,ds
+ add dx,1000h
+ mov ds,dx
+.nowrap:
+ dec ecx
+ jnz .checksum
+ pop ds
- and edx,edx ; Should be zero
+ and eax,eax ; Should be zero
jz all_read ; We're cool, go for it!
;
@@ -647,15 +672,23 @@ 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
+MaxInitDataSize equ 96 << 10
+MaxLMA equ 0x7c00+SECTOR_SIZE+MaxInitDataSize
+SectorPtrs times MaxInitDataSize >> SECTOR_SHIFT dd 0
+SectorPtrsEnd equ $
+
; ----------------------------------------------------------------------------
; End of code and data that have to be in the first sector
; ----------------------------------------------------------------------------
+ section .text16
all_read:
;
; Let the user (and programmer!) know we got this far. This used to be
@@ -681,7 +714,19 @@ expand_super:
stosd ; Store expanded byte
loop .loop
+
;
-; Fall through to the mainline code...
+; Common initialization code
;
- section .text
+%include "init.inc"
+
+ pushad
+ mov eax,ROOT_FS_OPS
+ movzx dx,byte [DriveNumber]
+ ; DH = 0: we are boot from disk not CDROM
+ mov ecx,[bsHidden]
+ mov ebx,[bsHidden+4]
+ mov si,[bsHeads]
+ mov di,[bsSecPerTrack]
+ pm_call fs_init
+ popad
diff --git a/core/dnsresolv.inc b/core/dnsresolv.inc
deleted file mode 100644
index c2c429cb..00000000
--- a/core/dnsresolv.inc
+++ /dev/null
@@ -1,389 +0,0 @@
-; -*- fundamental -*-
-; -----------------------------------------------------------------------
-;
-; Copyright 2004-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,
-; Bostom MA 02111-1307, USA; either version 2 of the License, or
-; (at your option) any later version; incorporated herein by reference.
-;
-; -----------------------------------------------------------------------
-
-;
-; dnsresolv.inc
-;
-; Very simple DNS resolver (assumes recursion-enabled DNS server;
-; this should be the normal thing for client-serving DNS servers.)
-;
-
-DNS_PORT equ htons(53) ; Default DNS port
-DNS_MAX_PACKET equ 512 ; Defined by protocol
-; TFTP uses the range 49152-57343
-DNS_LOCAL_PORT equ htons(60053) ; All local DNS queries come from this port #
-DNS_MAX_SERVERS equ 4 ; Max no of DNS servers
-
- section .text
-
-;
-; Turn a string in DS:SI into a DNS "label set" in ES:DI.
-; On return, DI points to the first byte after the label set,
-; and SI to the terminating byte.
-;
-; On return, DX contains the number of dots encountered.
-;
-dns_mangle:
- push ax
- push bx
- xor dx,dx
-.isdot:
- inc dx
- xor al,al
- mov bx,di
- stosb
-.getbyte:
- lodsb
- and al,al
- jz .endstring
- cmp al,':'
- jz .endstring
- cmp al,'.'
- je .isdot
- inc byte [es:bx]
- stosb
- jmp .getbyte
-.endstring:
- dec si
- dec dx ; We always counted one high
- cmp byte [es:bx],0
- jz .done
- xor al,al
- stosb
-.done:
- pop bx
- pop ax
- ret
-
-;
-; Compare two sets of DNS labels, in DS:SI and ES:DI; the one in SI
-; is allowed pointers relative to a packet in DNSRecvBuf.
-;
-; Assumes DS == ES. ZF = 1 if same; no registers changed.
-; (Note: change reference to [di] to [es:di] to remove DS == ES assumption)
-;
-dns_compare:
- pusha
-%if 0
-
-.label:
- lodsb
- cmp al,0C0h
- jb .noptr
- and al,03Fh ; Get pointer value
- mov ah,al ; ... in network byte order!
- lodsb
- mov si,DNSRecvBuf
- add si,ax
- jmp .label
-.noptr:
- cmp al,[di]
- jne .done ; Mismatch
- inc di
- movzx cx,al ; End label?
- and cx,cx ; ZF = 1 if match
- jz .done
-
- ; We have a string of bytes that need to match now
- repe cmpsb
- je .label
-
-.done:
-%else
- xor ax,ax
-%endif
- popa
- ret
-
-;
-; Skip past a DNS label set in DS:SI.
-;
-dns_skiplabel:
- push ax
- xor ax,ax ; AH == 0
-.loop:
- lodsb
- cmp al,0C0h ; Pointer?
- jae .ptr
- and al,al
- jz .done
- add si,ax
- jmp .loop
-.ptr:
- inc si ; Pointer is two bytes
-.done:
- pop ax
- ret
-
- ; DNS header format
- struc dnshdr
-.id: resw 1
-.flags: resw 1
-.qdcount: resw 1
-.ancount: resw 1
-.nscount: resw 1
-.arcount: resw 1
- endstruc
-
- ; DNS query
- struc dnsquery
-.qtype: resw 1
-.qclass: resw 1
- endstruc
-
- ; DNS RR
- struc dnsrr
-.type: resw 1
-.class: resw 1
-.ttl: resd 1
-.rdlength: resw 1
-.rdata: equ $
- endstruc
-
- section .bss2
- alignb 2
-DNSSendBuf resb DNS_MAX_PACKET
-DNSRecvBuf resb DNS_MAX_PACKET
-LocalDomain resb 256 ; Max possible length
-DNSServers resd DNS_MAX_SERVERS
-
- section .data
-pxe_udp_write_pkt_dns:
-.status: dw 0 ; Status
-.sip: dd 0 ; Server IP
-.gip: dd 0 ; Gateway IP
-.lport: dw DNS_LOCAL_PORT ; Local port
-.rport: dw DNS_PORT ; Remote port
-.buffersize: dw 0 ; Size of packet
-.buffer: dw DNSSendBuf, 0 ; off, seg of buffer
-
-pxe_udp_read_pkt_dns:
-.status: dw 0 ; Status
-.sip: dd 0 ; Source IP
-.dip: dd 0 ; Destination (our) IP
-.rport: dw DNS_PORT ; Remote port
-.lport: dw DNS_LOCAL_PORT ; Local port
-.buffersize: dw DNS_MAX_PACKET ; Max packet size
-.buffer: dw DNSRecvBuf, 0 ; off, seg of buffer
-
-LastDNSServer dw DNSServers
-
-; Actual resolver function
-; Points to a null-terminated or :-terminated string in DS:SI
-; and returns the name in EAX if it exists and can be found.
-; If EAX = 0 on exit, the lookup failed.
-;
-; No segment assumptions permitted.
-;
- section .text
-dns_resolv:
- push ds
- push es
- push di
- push bx
- push cx
- push dx
-
- push cs
- pop es ; ES <- CS
-
- ; First, build query packet
- mov di,DNSSendBuf+dnshdr.flags
- inc word [es:di-2] ; New query ID
- mov ax,htons(0100h) ; Recursion requested
- stosw
- mov ax,htons(1) ; One question
- stosw
- xor ax,ax ; No answers, NS or ARs
- stosw
- stosw
- stosw
-
- call dns_mangle ; Convert name to DNS labels
-
- push cs ; DS <- CS
- pop ds
-
- push si ; Save pointer to after DNS string
-
- ; Initialize...
- mov eax,[MyIP]
- mov [pxe_udp_read_pkt_dns.dip],eax
-
- and dx,dx
- jnz .fqdn ; If we have dots, assume it's FQDN
- dec di ; Remove final null
- mov si,LocalDomain
- call strcpy ; Uncompressed DNS label set so it ends in null
-.fqdn:
-
- mov ax,htons(1)
- stosw ; QTYPE = 1 = A
- stosw ; QCLASS = 1 = IN
-
- sub di,DNSSendBuf
- mov [pxe_udp_write_pkt_dns.buffersize],di
-
- ; Now, send it to the nameserver(s)
- ; Outer loop: exponential backoff
- ; Inner loop: scan the various DNS servers
-
- mov bx,TimeoutTable
-.backoff:
- movzx dx,byte [bx]
- mov si,DNSServers
-.servers:
- cmp si,[LastDNSServer]
- jb .moreservers
-
-.nomoreservers:
- inc bx
- cmp bx,TimeoutTableEnd
- jb .backoff
-
- xor eax,eax ; Nothing...
-.done:
- pop si
- pop dx
- pop cx
- pop bx
- pop di
- pop es
- pop ds
- ret
-
-.moreservers:
- lodsd ; EAX <- next server
- push si
- push bx
- push cx
- push dx
-
- mov word [pxe_udp_write_pkt_dns.status],0
-
- mov [pxe_udp_write_pkt_dns.sip],eax
- mov [pxe_udp_read_pkt_dns.sip],eax
- xor eax,[MyIP]
- and eax,[Netmask]
- jz .nogw
- mov eax,[Gateway]
-.nogw:
- mov [pxe_udp_write_pkt_dns.gip],eax
-
- mov di,pxe_udp_write_pkt_dns
- mov bx,PXENV_UDP_WRITE
- call pxenv
- jc .timeout ; Treat failed transmit as timeout
- cmp word [pxe_udp_write_pkt_dns.status],0
- jne .timeout
-
- mov cx,[BIOS_timer]
-.waitrecv:
- mov ax,[BIOS_timer]
- sub ax,cx
- cmp ax,dx
- jae .timeout
-
- mov word [pxe_udp_read_pkt_dns.status],0
- mov word [pxe_udp_read_pkt_dns.buffersize],DNS_MAX_PACKET
- mov di,pxe_udp_read_pkt_dns
- mov bx,PXENV_UDP_READ
- call pxenv
- and ax,ax
- jnz .waitrecv
- cmp [pxe_udp_read_pkt_dns.status],ax
- jnz .waitrecv
-
- ; Got a packet, deal with it...
- mov si,DNSRecvBuf
- lodsw
- cmp ax,[DNSSendBuf] ; ID
- jne .waitrecv ; Not ours
-
- lodsw ; flags
- xor al,80h ; Query#/Answer bit
- test ax,htons(0F80Fh)
- jnz .badness
-
- lodsw
- xchg ah,al ; ntohs
- mov cx,ax ; Questions echoed
- lodsw
- xchg ah,al ; ntohs
- push ax ; Replies
- lodsw ; NS records
- lodsw ; Authority records
-
- jcxz .qskipped
-.skipq:
- call dns_skiplabel ; Skip name
- add si,4 ; Skip question trailer
- loop .skipq
-
-.qskipped:
- pop cx ; Number of replies
- jcxz .badness
-
-.parseanswer:
- mov di,DNSSendBuf+dnshdr_size
- call dns_compare
- pushf
- call dns_skiplabel
- mov ax,[si+8] ; RDLENGTH
- xchg ah,al ; ntohs
- popf
- jnz .notsame
- cmp dword [si],htons(1)*0x10001 ; TYPE = A, CLASS = IN?
- jne .notsame
- cmp ax,4 ; RDLENGTH = 4?
- jne .notsame
- ;
- ; We hit paydirt here...
- ;
- mov eax,[si+10]
-.gotresult:
- add sp,8 ; Drop timeout information
- jmp .done
-
-.notsame:
- add si,10
- add si,ax
- loop .parseanswer
-
-.badness:
- ; We got back no data from this server.
- ; Unfortunately, for a recursive, non-authoritative
- ; query there is no such thing as an NXDOMAIN reply,
- ; which technically means we can't draw any
- ; conclusions. However, in practice that means the
- ; domain doesn't exist. If this turns out to be a
- ; problem, we may want to add code to go through all
- ; the servers before giving up.
-
- ; If the DNS server wasn't capable of recursion, and
- ; isn't capable of giving us an authoritative reply
- ; (i.e. neither AA or RA set), then at least try a
- ; different setver...
-
- test word [DNSRecvBuf+dnshdr.flags],htons(0480h)
- jz .timeout
-
- xor eax,eax
- jmp .gotresult
-
-.timeout:
- pop dx
- pop cx
- pop bx
- pop si
- jmp .servers
diff --git a/core/ext2_fs.inc b/core/ext2_fs.inc
deleted file mode 100644
index e84efb14..00000000
--- a/core/ext2_fs.inc
+++ /dev/null
@@ -1,183 +0,0 @@
-; -----------------------------------------------------------------------
-;
-; Copyright 1998-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., 675 Mass Ave, Cambridge MA 02139,
-; USA; either version 2 of the License, or (at your option) any later
-; version; incorporated herein by reference.
-;
-; -----------------------------------------------------------------------
-
-;
-; ext2_fs.inc
-;
-; NASM include file for ext2fs data structures
-;
-
-%define EXT2_SUPER_MAGIC 0xEF53
-
-%define EXT2_GOOD_OLD_REV 0 ; The good old (original) format
-%define EXT2_DYNAMIC_REV 1 ; V2 format w/ dynamic inode sizes
-%define EXT2_GOOD_OLD_INODE_SIZE 128
-
-; Special inode numbers
-%define EXT2_BAD_INO 1 ; Bad blocks inode
-%define EXT2_ROOT_INO 2 ; Root inode
-%define EXT2_BOOT_LOADER_INO 5 ; Boot loader inode
-%define EXT2_UNDEL_DIR_INO 6 ; Undelete directory inode
-%define EXT3_RESIZE_INO 7 ; Reserved group descriptors inode
-%define EXT3_JOURNAL_INO 8 ; Journal inode
-
-; We're readonly, so we only care about incompat features.
-%define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
-%define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
-%define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
-%define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
-%define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
-%define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
-
-%define EXT2_NDIR_BLOCKS 12
-%define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
-%define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1)
-%define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1)
-%define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1)
-
-;
-; File types and file modes
-;
-%define S_IFDIR 0040000o ; Directory
-%define S_IFCHR 0020000o ; Character device
-%define S_IFBLK 0060000o ; Block device
-%define S_IFREG 0100000o ; Regular file
-%define S_IFIFO 0010000o ; FIFO
-%define S_IFLNK 0120000o ; Symbolic link
-%define S_IFSOCK 0140000o ; Socket
-
-%define S_IFSHIFT 12
-
-%define T_IFDIR (S_IFDIR >> S_IFSHIFT)
-%define T_IFCHR (S_IFCHR >> S_IFSHIFT)
-%define T_IFBLK (S_IFBLK >> S_IFSHIFT)
-%define T_IFREG (S_IFREG >> S_IFSHIFT)
-%define T_IFIFO (S_IFIFO >> S_IFSHIFT)
-%define T_IFLNK (S_IFLNK >> S_IFSHIFT)
-%define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
-
-;
-; Structure definition for the ext2 superblock
-;
- struc ext2_super_block
-s_inodes_count resd 1 ; Inodes count
-s_blocks_count resd 1 ; Blocks count
-s_r_blocks_count resd 1 ; Reserved blocks count
-s_free_blocks_count resd 1 ; Free blocks count
-s_free_inodes_count resd 1 ; Free inodes count
-s_first_data_block resd 1 ; First Data Block
-s_log_block_size resd 1 ; Block size
-s_log_frag_size resd 1 ; Fragment size
-s_blocks_per_group resd 1 ; # Blocks per group
-s_frags_per_group resd 1 ; # Fragments per group
-s_inodes_per_group resd 1 ; # Inodes per group
-s_mtime resd 1 ; Mount time
-s_wtime resd 1 ; Write time
-s_mnt_count resw 1 ; Mount count
-s_max_mnt_count resw 1 ; Maximal mount count
-s_magic resw 1 ; Magic signature
-s_state resw 1 ; File system state
-s_errors resw 1 ; Behaviour when detecting errors
-s_minor_rev_level resw 1 ; minor revision level
-s_lastcheck resd 1 ; time of last check
-s_checkinterval resd 1 ; max. time between checks
-s_creator_os resd 1 ; OS
-s_rev_level resd 1 ; Revision level
-s_def_resuid resw 1 ; Default uid for reserved blocks
-s_def_resgid resw 1 ; Default gid for reserved blocks
-s_first_ino resd 1 ; First non-reserved inode
-s_inode_size resw 1 ; size of inode structure
-s_block_group_nr resw 1 ; block group # of this superblock
-s_feature_compat resd 1 ; compatible feature set
-s_feature_incompat resd 1 ; incompatible feature set
-s_feature_ro_compat resd 1 ; readonly-compatible feature set
-s_uuid resb 16 ; 128-bit uuid for volume
-s_volume_name resb 16 ; volume name
-s_last_mounted resb 64 ; directory where last mounted
-s_algorithm_usage_bitmap resd 1 ; For compression
-s_prealloc_blocks resb 1 ; Nr of blocks to try to preallocate
-s_prealloc_dir_blocks resb 1 ; Nr to preallocate for dirs
-s_padding1 resw 1
-s_reserved resd 204 ; Padding to the end of the block
- endstruc
-
-%ifndef DEPEND
-%if ext2_super_block_size != 1024
-%error "ext2_super_block definition bogus"
-%endif
-%endif
-
-;
-; Structure definition for the ext2 inode
-;
- struc ext2_inode
-i_mode resw 1 ; File mode
-i_uid resw 1 ; Owner Uid
-i_size resd 1 ; Size in bytes
-i_atime resd 1 ; Access time
-i_ctime resd 1 ; Creation time
-i_mtime resd 1 ; Modification time
-i_dtime resd 1 ; Deletion Time
-i_gid resw 1 ; Group Id
-i_links_count resw 1 ; Links count
-i_blocks resd 1 ; Blocks count
-i_flags resd 1 ; File flags
-l_i_reserved1 resd 1
-i_block resd EXT2_N_BLOCKS ; Pointer to blocks
-i_version resd 1 ; File version (for NFS)
-i_file_acl resd 1 ; File ACL
-i_dir_acl resd 1 ; Directory ACL
-i_faddr resd 1 ; Fragment address
-l_i_frag resb 1 ; Fragment number
-l_i_fsize resb 1 ; Fragment size
-i_pad1 resw 1
-l_i_reserved2 resd 2
- endstruc
-
-%ifndef DEPEND
-%if ext2_inode_size != 128
-%error "ext2_inode definition bogus"
-%endif
-%endif
-
-;
-; Structure definition for ext2 block group descriptor
-;
- struc ext2_group_desc
-bg_block_bitmap resd 1 ; Block bitmap block
-bg_inode_bitmap resd 1 ; Inode bitmap block
-bg_inode_table resd 1 ; Inode table block
-bg_free_blocks_count resw 1 ; Free blocks count
-bg_free_inodes_count resw 1 ; Free inodes count
-bg_used_dirs_count resw 1 ; Used inodes count
-bg_pad resw 1
-bg_reserved resd 3
- endstruc
-
-%ifndef DEPEND
-%if ext2_group_desc_size != 32
-%error "ext2_group_desc definition bogus"
-%endif
-%endif
-
-%define ext2_group_desc_lg2size 5
-
-;
-; Structure definition for ext2 directory entry
-;
- struc ext2_dir_entry
-d_inode resd 1 ; Inode number
-d_rec_len resw 1 ; Directory entry length
-d_name_len resb 1 ; Name length
-d_file_type resb 1 ; File type
-d_name equ $
- endstruc
diff --git a/core/extern.inc b/core/extern.inc
new file mode 100644
index 00000000..95a9c88d
--- /dev/null
+++ b/core/extern.inc
@@ -0,0 +1,26 @@
+;
+; extern.inc
+;
+; Prototypes for external functions
+
+%ifndef EXTERN_INC
+%define EXTERN_INC
+
+ ; rllpack.c
+ extern rllpack, rllunpack
+
+ ; hello.c
+ extern hello
+
+ ; fs.c
+ extern fs_init, searchdir, getfssec, mangle_name, load_config
+ extern unmangle_name, close_file
+
+ ; dir.c
+ extern opendir, readdir, closedir
+%if IS_PXELINUX
+ ; pxe.c
+ extern unload_pxe, reset_pxe
+%endif
+
+%endif ; EXTERN_INC
diff --git a/core/extlinux.asm b/core/extlinux.asm
index ac5fb6f0..1ac749bc 100644
--- a/core/extlinux.asm
+++ b/core/extlinux.asm
@@ -18,914 +18,19 @@
%define IS_EXTLINUX 1
%include "head.inc"
-%include "ext2_fs.inc"
;
; Some semi-configurable constants... change on your own risk.
;
my_id equ extlinux_id
-; NASM 0.98.38 croaks if these are equ's rather than macros...
-FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
-FILENAME_MAX equ (1 << FILENAME_MAX_LG2) ; Max mangled filename size
-NULLFILE equ 0 ; Null character == empty filename
-NULLOFFSET equ 0 ; Position in which to look
-retry_count equ 16 ; How patient are we with the disk?
-%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
-LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
-
-MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
-MAX_OPEN equ (1 << MAX_OPEN_LG2)
-
-SECTOR_SHIFT equ 9
-SECTOR_SIZE equ (1 << SECTOR_SHIFT)
-
-MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
-SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
- ; (should be >= FILENAME_MAX)
-
-ROOT_DIR_WORD equ 0x002F
-CUR_DIR_DWORD equ 0x00002F2E
-
-;
-; The following structure is used for "virtual kernels"; i.e. LILO-style
-; option labels. The options we permit here are `kernel' and `append
-; Since there is no room in the bottom 64K for all of these, we
-; stick them in high memory and copy them down before we need them.
-;
- struc vkernel
-vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
-vk_rname: resb FILENAME_MAX ; Real name
-vk_appendlen: resw 1
-vk_type: resb 1 ; Type of file
- alignb 4
-vk_append: resb max_cmd_len+1 ; Command line
- alignb 4
-vk_end: equ $ ; Should be <= vk_size
- endstruc
-
-;
-; File structure. This holds the information for each currently open file.
-;
- struc open_file_t
-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
-file_mode resw 1
- endstruc
-
-%ifndef DEPEND
-%if (open_file_t_size & (open_file_t_size-1))
-%error "open_file_t is not a power of 2"
-%endif
-%endif
-
-; ---------------------------------------------------------------------------
-; BEGIN CODE
-; ---------------------------------------------------------------------------
-
-;
-; Memory below this point is reserved for the BIOS and the MBR
-;
- section .earlybss
-trackbufsize equ 8192
-trackbuf resb trackbufsize ; Track buffer goes here
- ; ends at 2800h
-
- section .bss
-SuperBlock resb 1024 ; ext2 superblock
-ClustSize resd 1 ; Bytes/cluster ("block")
-ClustMask resd 1 ; Sectors/cluster - 1
-PtrsPerBlock1 resd 1 ; Pointers/cluster
-PtrsPerBlock2 resd 1 ; (Pointers/cluster)^2
-DriveNumber resb 1 ; BIOS drive number
-ClustShift resb 1 ; Shift count for sectors/cluster
-ClustByteShift resb 1 ; Shift count for bytes/cluster
-
- alignb open_file_t_size
-Files resb MAX_OPEN*open_file_t_size
-
-;
-; Common bootstrap code for disk-based derivatives
-;
-%include "diskstart.inc"
-
-;
-; Load the real (ext2) superblock; 1024 bytes long at offset 1024
-;
- mov bx,SuperBlock
- mov eax,1024 >> SECTOR_SHIFT
- mov bp,ax
- call getlinsecsr
-
-;
-; Compute some values...
-;
- xor edx,edx
- inc edx
-
- ; s_log_block_size = log2(blocksize) - 10
- mov cl,[SuperBlock+s_log_block_size]
- add cl,10
- mov [ClustByteShift],cl
- mov eax,edx
- shl eax,cl
- mov [ClustSize],eax
-
- sub cl,SECTOR_SHIFT
- mov [ClustShift],cl
- shr eax,SECTOR_SHIFT
- mov [SecPerClust],eax
- dec eax
- mov [ClustMask],eax
-
- add cl,SECTOR_SHIFT-2 ; 4 bytes/pointer
- shl edx,cl
- mov [PtrsPerBlock1],edx
- shl edx,cl
- mov [PtrsPerBlock2],edx
-
-;
-; Common initialization code
-;
-%include "init.inc"
-%include "cpuinit.inc"
-
-;
-; Initialize the metadata cache
-;
- call initcache
-
-;
-; Now, everything is "up and running"... patch kaboom for more
-; verbosity and using the full screen system
-;
- ; E9 = JMP NEAR
- mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
-
-;
-; Now we're all set to start with our *real* business. First load the
-; configuration file (if any) and parse it.
-;
-; In previous versions I avoided using 32-bit registers because of a
-; rumour some BIOSes clobbered the upper half of 32-bit registers at
-; random. I figure, though, that if there are any of those still left
-; they probably won't be trying to install Linux on them...
-;
-; The code is still ripe with 16-bitisms, though. Not worth the hassle
-; to take'm out. In fact, we may want to put them back if we're going
-; to boot ELKS at some point.
-;
-
-;
-; Load configuration file
-;
-load_config:
- mov si,config_name ; Save config file name
- mov di,ConfigName
- call strcpy
- mov dword [CurrentDirName],CUR_DIR_DWORD ; Write './',0,0 to the CurrentDirName
- call build_curdir_str
-
- mov di,ConfigName
- call open
- jz no_config_file
-
-;
-; Now we have the config file open. Parse the config file and
-; run the user interface.
-;
-%include "ui.inc"
-
-;
-; getlinsec_ext: same as getlinsec, except load any sector from the zero
-; block as all zeros; use to load any data derived
-; from an ext2 block pointer, i.e. anything *except the
-; superblock.*
-;
-getonesec_ext:
- mov bp,1
-
-getlinsec_ext:
- cmp eax,[SecPerClust]
- jae getlinsecsr ; Nothing fancy
-
- ; If we get here, at least part of what we want is in the
- ; zero block. Zero one sector at a time and loop.
- push eax
- push cx
- xchg di,bx
- xor eax,eax
- mov cx,SECTOR_SIZE >> 2
- rep stosd
- xchg di,bx
- pop cx
- pop eax
- inc eax
- dec bp
- jnz getlinsec_ext
- ret
-
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- ret
-;
-; open_inode:
-; Open a file indicated by an inode number in EAX
-;
-; NOTE: This file considers finding a zero-length file an
-; error. This is so we don't have to deal with that special
-; case elsewhere in the program (most loops have the test
-; at the end).
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; ThisInode = the first 128 bytes of the inode
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES.
-;
-open_inode.allocate_failure:
- xor eax,eax
- pop bx
- pop di
- ret
-
-open_inode:
- push di
- push bx
- call allocate_file
- jnz .allocate_failure
-
- push cx
- push gs
- ; First, get the appropriate inode group and index
- dec eax ; There is no inode 0
- xor edx,edx
- mov [bx+file_sector],edx
- div dword [SuperBlock+s_inodes_per_group]
- ; EAX = inode group; EDX = inode within group
- push edx
-
- ; Now, we need the block group descriptor.
- ; To get that, we first need the relevant descriptor block.
-
- shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
- xor edx,edx
- div dword [ClustSize]
- ; eax = block #, edx = offset in block
- add eax,dword [SuperBlock+s_first_data_block]
- inc eax ; s_first_data_block+1
- mov cl,[ClustShift]
- shl eax,cl
- push edx
- shr edx,SECTOR_SHIFT
- add eax,edx
- pop edx
- and dx,SECTOR_SIZE-1
- call getcachesector ; Get the group descriptor
- add si,dx
- mov esi,[gs:si+bg_inode_table] ; Get inode table block #
- pop eax ; Get inode within group
- movzx edx, word [SuperBlock+s_inode_size]
- mul edx
- ; edx:eax = byte offset in inode table
- div dword [ClustSize]
- ; eax = block # versus inode table, edx = offset in block
- add eax,esi
- shl eax,cl ; Turn into sector
- push dx
- shr edx,SECTOR_SHIFT
- add eax,edx
- mov [bx+file_in_sec],eax
- pop dx
- and dx,SECTOR_SIZE-1
- mov [bx+file_in_off],dx
-
- call getcachesector
- add si,dx
- mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
- mov di,ThisInode
- gs rep movsd
-
- mov ax,[ThisInode+i_mode]
- mov [bx+file_mode],ax
- mov eax,[ThisInode+i_size]
- mov [bx+file_bytesleft],eax
- mov si,bx
- and eax,eax ; ZF clear unless zero-length file
- pop gs
- pop cx
- pop bx
- pop di
- ret
-
- section .bss
- alignb 4
-ThisInode resb EXT2_GOOD_OLD_INODE_SIZE ; The most recently opened inode
-
- section .text
-;
-; close_file:
-; Deallocates a file structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_file:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_bytesleft
- xor si,si
-.closed: ret
-
-;
-; searchdir:
-; Search the root directory for a pre-mangled filename in DS:DI.
-;
-; NOTE: This file considers finding a zero-length file an
-; error. This is so we don't have to deal with that special
-; case elsewhere in the program (most loops have the test
-; at the end).
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; DX:AX = EAX = file length in bytes
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES; *** IS THIS CORRECT ***?
-;
-searchdir:
- push bx
- push cx
- push bp
- mov byte [SymlinkCtr],MAX_SYMLINKS
-
- mov eax,[CurrentDir]
-.begin_path:
-.leadingslash:
- cmp byte [di],'/' ; Absolute filename?
- jne .gotdir
- mov eax,EXT2_ROOT_INO
- inc di ; Skip slash
- jmp .leadingslash
-.gotdir:
-
- ; At this point, EAX contains the directory inode,
- ; and DS:DI contains a pathname tail.
-.open:
- push eax ; Save directory inode
-
- call open_inode
- jz .missing ; If error, done
-
- mov cx,[si+file_mode]
- shr cx,S_IFSHIFT ; Get file type
-
- cmp cx,T_IFDIR
- je .directory
-
- add sp,4 ; Drop directory inode
-
- cmp cx,T_IFREG
- je .file
- cmp cx,T_IFLNK
- je .symlink
-
- ; Otherwise, something bad...
-.err:
- call close_file
-.err_noclose:
- xor eax,eax
- xor si,si
- cwd ; DX <- 0
-
-.done:
- and eax,eax ; Set/clear ZF
- pop bp
- pop cx
- pop bx
- ret
-
-.missing:
- add sp,4 ; Drop directory inode
- jmp .done
-
- ;
- ; It's a file.
- ;
-.file:
- cmp byte [di],0 ; End of path?
- je .done ; If so, done
- jmp .err ; Otherwise, error
-
- ;
- ; It's a directory.
- ;
-.directory:
- pop dword [ThisDir] ; Remember what directory we're searching
-
- cmp byte [di],0 ; More path?
- je .err ; If not, bad
-
-.skipslash: ; Skip redundant slashes
- cmp byte [di],'/'
- jne .readdir
- inc di
- jmp .skipslash
-
-.readdir:
- mov cx,[SecPerClust]
- push cx
- shl cx,SECTOR_SHIFT
- mov bx,trackbuf
- add cx,bx
- mov [EndBlock],cx
- pop cx
- push bx
- call getfssec
- pop bx
- pushf ; Save EOF flag
- push si ; Save filesystem pointer
-.getent:
- cmp bx,[EndBlock]
- jae .endblock
-
- push di
- cmp dword [bx+d_inode],0 ; Zero inode = void entry
- je .nope
-
- movzx cx,byte [bx+d_name_len]
- lea si,[bx+d_name]
- repe cmpsb
- je .maybe
-.nope:
- pop di
- add bx,[bx+d_rec_len]
- jmp .getent
-
-.endblock:
- pop si
- popf
- jnc .readdir ; There is more
- jmp .err ; Otherwise badness...
-
-.maybe:
- mov eax,[bx+d_inode]
-
- ; Does this match the end of the requested filename?
- cmp byte [di],0
- je .finish
- cmp byte [di],'/'
- jne .nope
-
- ; We found something; now we need to open the file
-.finish:
- pop bx ; Adjust stack (di)
- pop si
- call close_file ; Close directory
- pop bx ; Adjust stack (flags)
- jmp .open
-
- ;
- ; It's a symlink. We have to determine if it's a fast symlink
- ; (data stored in the inode) or not (data stored as a regular
- ; file.) Either which way, we start from the directory
- ; which we just visited if relative, or from the root directory
- ; if absolute, and append any remaining part of the path.
- ;
-.symlink:
- dec byte [SymlinkCtr]
- jz .err ; Too many symlink references
-
- cmp eax,SYMLINK_SECTORS*SECTOR_SIZE
- jae .err ; Symlink too long
-
- ; Computation for fast symlink, as defined by ext2/3 spec
- xor ecx,ecx
- cmp [ThisInode+i_file_acl],ecx
- setne cl ; ECX <- i_file_acl ? 1 : 0
- cmp [ThisInode+i_blocks],ecx
- jne .slow_symlink
-
- ; It's a fast symlink
-.fast_symlink:
- call close_file ; We've got all we need
- mov si,ThisInode+i_block
-
- push di
- mov di,SymlinkTmpBuf
- mov ecx,eax
- rep movsb
- pop si
-
-.symlink_finish:
- cmp byte [si],0
- je .no_slash
- mov al,'/'
- stosb
-.no_slash:
- mov bp,SymlinkTmpBufEnd
- call strecpy
- jc .err_noclose ; Buffer overflow
-
- ; Now copy it to the "real" buffer; we need to have
- ; two buffers so we avoid overwriting the tail on the
- ; next copy
- mov si,SymlinkTmpBuf
- mov di,SymlinkBuf
- push di
- call strcpy
- pop di
- mov eax,[ThisDir] ; Resume searching previous directory
- jmp .begin_path
-
-.slow_symlink:
- mov bx,SymlinkTmpBuf
- mov cx,SYMLINK_SECTORS
- call getfssec
- ; The EOF closed the file
-
- mov si,di ; SI = filename tail
- mov di,SymlinkTmpBuf
- add di,ax ; AX = file length
- jmp .symlink_finish
-
-
- section .bss
- alignb 4
-SymlinkBuf resb SYMLINK_SECTORS*SECTOR_SIZE+64
-SymlinkTmpBuf equ trackbuf
-SymlinkTmpBufEnd equ trackbuf+SYMLINK_SECTORS*SECTOR_SIZE+64
-ThisDir resd 1
-EndBlock resw 1
-SymlinkCtr resb 1
-
- section .text
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-; to by ES:DI; ends on encountering any whitespace.
-; DI is preserved.
-;
-; This verifies that a filename is < FILENAME_MAX characters,
-; doesn't contain whitespace, zero-pads the output buffer,
-; and removes redundant slashes,
-; so "repe cmpsb" can do a compare, and the
-; path-searching routine gets a bit of an easier job.
-;
-; FIX: we may want to support \-escapes here (and this would
-; be the place.)
-;
-mangle_name:
- push di
- push bx
- xor ax,ax
- mov cx,FILENAME_MAX-1
- mov bx,di
-
-.mn_loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .mn_end
- cmp al,ah ; Repeated slash?
- je .mn_skip
- xor ah,ah
- cmp al,'/'
- jne .mn_ok
- mov ah,al
-.mn_ok stosb
-.mn_skip: loop .mn_loop
-.mn_end:
- cmp bx,di ; At the beginning of the buffer?
- jbe .mn_zero
- cmp byte [di-1],'/' ; Terminal slash?
- jne .mn_zero
-.mn_kill: dec di ; If so, remove it
- inc cx
- jmp short .mn_end
-.mn_zero:
- inc cx ; At least one null byte
- xor ax,ax ; Zero-fill name
- rep stosb
- pop bx
- pop di
- ret ; Done
-
-;
-; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
-; filename to the conventional representation. This is needed
-; for the BOOT_IMAGE= parameter for the kernel.
-;
-; DS:SI -> input mangled file name
-; ES:DI -> output buffer
-;
-; On return, DI points to the first byte after the output name,
-; which is set to a null byte.
-;
-unmangle_name: call strcpy
- dec di ; Point to final null byte
- ret
-
-;
-;
-; kaboom2: once everything is loaded, replace the part of kaboom
-; starting with "kaboom.patch" with this part
-
-kaboom2:
- mov si,err_bootfailed
- call writestr
- cmp byte [kaboom.again+1],18h ; INT 18h version?
- je .int18
- call getchar
- call vgaclearmode
- int 19h ; And try once more to boot...
-.norge: jmp short .norge ; If int 19h returned; this is the end
-.int18:
- call vgaclearmode
- int 18h
-.noreg: jmp short .noreg ; Nynorsk
-
-
-;
-; linsector: Convert a linear sector index in a file to a linear sector number
-; EAX -> linear sector number
-; DS:SI -> open_file_t
-;
-; Returns next sector number in EAX; CF on EOF (not an error!)
-;
-linsector:
- push gs
- push ebx
- push esi
- push edi
- push ecx
- push edx
- push ebp
-
- push eax ; Save sector index
- mov cl,[ClustShift]
- shr eax,cl ; Convert to block number
- push eax
- mov eax,[si+file_in_sec]
- mov bx,si
- call getcachesector ; Get inode
- add si,[bx+file_in_off] ; Get *our* inode
- pop eax
- lea ebx,[i_block+4*eax]
- cmp eax,EXT2_NDIR_BLOCKS
- jb .direct
- mov ebx,i_block+4*EXT2_IND_BLOCK
- sub eax,EXT2_NDIR_BLOCKS
- mov ebp,[PtrsPerBlock1]
- cmp eax,ebp
- jb .ind1
- mov ebx,i_block+4*EXT2_DIND_BLOCK
- sub eax,ebp
- mov ebp,[PtrsPerBlock2]
- cmp eax,ebp
- jb .ind2
- mov ebx,i_block+4*EXT2_TIND_BLOCK
- sub eax,ebp
-
-.ind3:
- ; Triple indirect; eax contains the block no
- ; with respect to the start of the tind area;
- ; ebx contains the pointer to the tind block.
- xor edx,edx
- div dword [PtrsPerBlock2]
- ; EAX = which dind block, EDX = pointer within dind block
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- call getcachesector
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
- mov eax,edx ; The ind2 code wants the remainder...
-
-.ind2:
- ; Double indirect; eax contains the block no
- ; with respect to the start of the dind area;
- ; ebx contains the pointer to the dind block.
- xor edx,edx
- div dword [PtrsPerBlock1]
- ; EAX = which ind block, EDX = pointer within ind block
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- call getcachesector
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
- mov eax,edx ; The int1 code wants the remainder...
-
-.ind1:
- ; Single indirect; eax contains the block no
- ; with respect to the start of the ind area;
- ; ebx contains the pointer to the ind block.
- push ax
- shr eax,SECTOR_SHIFT-2
- mov ebp,[gs:si+bx]
- shl ebp,cl
- add eax,ebp
- call getcachesector
- pop bx
- and bx,(SECTOR_SIZE >> 2)-1
- shl bx,2
-
-.direct:
- mov ebx,[gs:bx+si] ; Get the pointer
-
- pop eax ; Get the sector index again
- shl ebx,cl ; Convert block number to sector
- and eax,[ClustMask] ; Add offset within block
- add eax,ebx
-
- pop ebp
- pop edx
- pop ecx
- pop edi
- pop esi
- pop ebx
- pop gs
- ret
-
-;
-; getfssec: Get multiple sectors from a file
-;
-; Same as above, except SI is a pointer to a open_file_t
-;
-; ES:BX -> Buffer
-; DS:SI -> Pointer to open_file_t
-; 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:
- push ebp
- push eax
- push edx
- push edi
-
- movzx ecx,cx
- 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,ax
-.lenok:
-.getfragment:
- mov eax,[si+file_sector] ; Current start index
- mov edi,eax
- call linsector
- push eax ; Fragment start sector
- mov edx,eax
- xor ebp,ebp ; Fragment sector count
-.getseccnt:
- inc bp
- dec cx
- jz .do_read
- xor eax,eax
- mov ax,es
- shl ax,4
- add ax,bx ; Now DI = how far into 64K block we are
- not ax ; Bytes left in 64K block
- inc eax
- shr eax,SECTOR_SHIFT ; Sectors left in 64K block
- cmp bp,ax
- jnb .do_read ; Unless there is at least 1 more sector room...
- inc edi ; Sector index
- inc edx ; Linearly next sector
- mov eax,edi
- call linsector
- ; jc .do_read
- cmp edx,eax
- je .getseccnt
-.do_read:
- pop eax ; Linear start sector
- pushad
- call getlinsec_ext
- popad
- push bp
- shl bp,9
- add bx,bp ; Adjust buffer pointer
- pop bp
- add [si+file_sector],ebp ; Next sector index
- jcxz .done
- jnz .getfragment
- ; Fall through
-.done:
- pop ecx ; Sectors requested read
- shl ecx,SECTOR_SHIFT
- sub [si+file_bytesleft],ecx
- jnbe .noteof ; CF=0 in this case
- add ecx,[si+file_bytesleft] ; Actual number of bytes read
- call close_file
- stc ; We hit EOF
-.noteof:
- pop edi
- pop edx
- pop eax
- pop ebp
- ret
-
-build_curdir_str:
- ret
-
-; -----------------------------------------------------------------------------
-; Common modules
-; -----------------------------------------------------------------------------
-
-%include "getc.inc" ; getc et al
-%include "conio.inc" ; Console I/O
-%include "plaincon.inc" ; writechr
-%include "writestr.inc" ; String output
-%include "writehex.inc" ; Hexadecimal output
-%include "configinit.inc" ; Initialize configuration
-%include "parseconfig.inc" ; High-level config file handling
-%include "parsecmd.inc" ; Low-level config file handling
-%include "bcopy32.inc" ; 32-bit bcopy
-%include "loadhigh.inc" ; Load a file into high memory
-%include "font.inc" ; VGA font stuff
-%include "graphics.inc" ; VGA graphics
-%include "highmem.inc" ; High memory sizing
-%include "strcpy.inc" ; strcpy()
-%include "strecpy.inc" ; strcpy with end pointer check
-%include "cache.inc" ; Metadata disk cache
-%include "idle.inc" ; Idle handling
-%include "adv.inc" ; Auxillary Data Vector
-%include "localboot.inc" ; Disk-based local boot
-
-; -----------------------------------------------------------------------------
-; Begin data section
-; -----------------------------------------------------------------------------
-
- section .data
-copyright_str db ' Copyright (C) 1994-'
- asciidec YEAR
- db ' H. Peter Anvin et al', CR, LF, 0
-err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
- db 'a key to continue.', CR, LF, 0
-config_name db 'extlinux.conf',0 ; Unmangled form
-
-;
-; Config file keyword table
-;
-%include "keywords.inc"
-
-;
-; Extensions to search for (in *forward* order).
-;
- alignz 4
-exten_table: db '.cbt' ; COMBOOT (specific)
- db '.img' ; Disk image
- db '.bs', 0 ; Boot sector
- db '.com' ; COMBOOT (same as DOS)
- db '.c32' ; COM32
-exten_table_end:
- dd 0, 0 ; Need 8 null bytes here
-
-;
-; Misc initialized (data) variables
-;
-%ifdef debug ; This code for debugging only
-debug_magic dw 0D00Dh ; Debug code sentinel
-%endif
+ section .rodata
alignz 4
-BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
-BufSafeBytes dw trackbufsize ; = how many bytes?
-%ifndef DEPEND
-%if ( trackbufsize % SECTOR_SIZE ) != 0
-%error trackbufsize must be a multiple of SECTOR_SIZE
-%endif
-%endif
+ROOT_FS_OPS:
+ extern ext2_fs_ops
+ dd ext2_fs_ops
+ extern btrfs_fs_ops
+ dd btrfs_fs_ops
+ dd 0
+
+%include "diskfs.inc"
diff --git a/core/font.inc b/core/font.inc
index 4090e5af..12236358 100644
--- a/core/font.inc
+++ b/core/font.inc
@@ -16,7 +16,7 @@
;; VGA font handling code
;;
- section .text
+ section .text16
;
; loadfont: Load a .psf font file and install it onto the VGA console
@@ -141,12 +141,12 @@ vidrows_ok: mov [VidRows],al
popa
ret
- section .data
+ section .data16
alignz 2
VGAFontSize dw 16 ; Defaults to 16 byte font
UserFont db 0 ; Using a user-specified font
- section .bss1
+ section .bss16
alignb 4
GXPixCols resw 1 ; Graphics mode pixel columns
GXPixRows resw 1 ; Graphics mode pixel rows
diff --git a/core/fs.c b/core/fs.c
new file mode 100644
index 00000000..37808812
--- /dev/null
+++ b/core/fs.c
@@ -0,0 +1,284 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fs.h>
+#include <cache.h>
+
+/* The currently mounted filesystem */
+struct fs_info *this_fs = NULL;
+static struct fs_info fs;
+struct inode *this_inode = NULL;
+
+/* Actual file structures (we don't have malloc yet...) */
+struct file files[MAX_OPEN];
+
+/*
+ * Get an empty file structure
+ */
+static struct file *alloc_file(void)
+{
+ int i;
+ struct file *file = files;
+
+ for (i = 0; i < MAX_OPEN; i++) {
+ if (!file->fs)
+ return file;
+ file++;
+ }
+
+ return NULL;
+}
+
+/*
+ * Close and free a file structure
+ */
+static inline void free_file(struct file *file)
+{
+ memset(file, 0, sizeof *file);
+}
+
+void _close_file(struct file *file)
+{
+ if (file->fs)
+ file->fs->fs_ops->close_file(file);
+ free_file(file);
+}
+
+/*
+ * Convert between a 16-bit file handle and a file structure
+ */
+inline uint16_t file_to_handle(struct file *file)
+{
+ return file ? (file - files)+1 : 0;
+}
+inline struct file *handle_to_file(uint16_t handle)
+{
+ return handle ? &files[handle-1] : NULL;
+}
+
+void load_config(void)
+{
+ int err;
+ err = this_fs->fs_ops->load_config();
+
+#if 0
+ printf("Loading config file %s\n", err ? "failed" : "successed");
+#endif
+}
+
+void mangle_name(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ this_fs->fs_ops->mangle_name(dst, src);
+}
+
+
+void unmangle_name(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ dst = this_fs->fs_ops->unmangle_name(dst, src);
+
+ /* Update the di register to point to the last null char */
+ regs->edi.w[0] = OFFS_WRT(dst, regs->es);
+}
+
+
+void getfssec(com32sys_t *regs)
+{
+ int sectors;
+ bool have_more;
+ uint32_t bytes_read;
+ char *buf;
+ struct file *file;
+ uint16_t handle;
+
+ sectors = regs->ecx.w[0];
+
+ handle = regs->esi.w[0];
+ file = handle_to_file(handle);
+
+ buf = MK_PTR(regs->es, regs->ebx.w[0]);
+ bytes_read = file->fs->fs_ops->getfssec(file, buf, sectors, &have_more);
+
+ /*
+ * If we reach EOF, the filesystem driver will have already closed
+ * the underlying file... this really should be cleaner.
+ */
+ if (!have_more) {
+ _close_file(file);
+ regs->esi.w[0] = 0;
+ }
+
+ regs->ecx.l = bytes_read;
+}
+
+
+void searchdir(com32sys_t *regs)
+{
+ char *name = MK_PTR(regs->ds, regs->edi.w[0]);
+ struct inode *inode;
+ struct inode *parent;
+ struct file *file;
+ char part[256];
+ char *p;
+ int symlink_count = 6;
+
+#if 0
+ printf("filename: %s\n", name);
+#endif
+
+ if (!(file = alloc_file()))
+ goto err_no_close;
+ file->fs = this_fs;
+
+ /* if we have ->searchdir method, call it */
+ if (file->fs->fs_ops->searchdir) {
+ file->fs->fs_ops->searchdir(name, file);
+
+ if (file->open_file) {
+ regs->esi.w[0] = file_to_handle(file);
+ regs->eax.l = file->file_len;
+ regs->eflags.l &= ~EFLAGS_ZF;
+ return;
+ }
+
+ goto err;
+ }
+
+
+ /* else, try the generic-path-lookup method */
+ if (*name == '/') {
+ inode = this_fs->fs_ops->iget_root();
+ while(*name == '/')
+ name++;
+ } else {
+ inode = this_inode;
+ }
+ parent = inode;
+
+ while (*name) {
+ p = part;
+ while(*name && *name != '/')
+ *p++ = *name++;
+ *p = '\0';
+ inode = this_fs->fs_ops->iget(part, parent);
+ if (!inode)
+ goto err;
+ if (inode->mode == I_SYMLINK) {
+ if (!this_fs->fs_ops->follow_symlink ||
+ --symlink_count == 0 || /* limit check */
+ inode->size >= BLOCK_SIZE(this_fs))
+ goto err;
+ name = this_fs->fs_ops->follow_symlink(inode, name);
+ free_inode(inode);
+ continue;
+ }
+
+ /*
+ * For the relative path searching used in FAT and ISO fs.
+ */
+ if ((this_fs->fs_ops->fs_flags & FS_THISIND) && (this_inode != parent)){
+ if (this_inode)
+ free_inode(this_inode);
+ this_inode = parent;
+ }
+
+ if (parent != this_inode)
+ free_inode(parent);
+ parent = inode;
+ if (! *name)
+ break;
+ while(*name == '/')
+ name++;
+ }
+
+ file->inode = inode;
+ file->offset = 0;
+
+ regs->esi.w[0] = file_to_handle(file);
+ regs->eax.l = inode->size;
+ regs->eflags.l &= ~EFLAGS_ZF;
+ return;
+
+err:
+ _close_file(file);
+err_no_close:
+ regs->esi.w[0] = 0;
+ regs->eax.l = 0;
+ regs->eflags.l |= EFLAGS_ZF;
+}
+
+void close_file(com32sys_t *regs)
+{
+ uint16_t handle = regs->esi.w[0];
+ struct file *file;
+
+ if (handle) {
+ file = handle_to_file(handle);
+ _close_file(file);
+ }
+}
+
+/*
+ * it will do:
+ * initialize the memory management function;
+ * set up the vfs fs structure;
+ * initialize the device structure;
+ * invoke the fs-specific init function;
+ * initialize the cache if we need one;
+ * finally, get the current inode for relative path looking.
+ *
+ */
+void fs_init(com32sys_t *regs)
+{
+ uint8_t disk_devno = regs->edx.b[0];
+ uint8_t disk_cdrom = regs->edx.b[1];
+ sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
+ uint16_t disk_heads = regs->esi.w[0];
+ uint16_t disk_sectors = regs->edi.w[0];
+ int blk_shift = -1;
+ struct device *dev = NULL;
+ /* ops is a ptr list for several fs_ops */
+ const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l;
+
+ /* Initialize malloc() */
+ mem_init();
+
+ while ((blk_shift < 0) && *ops) {
+ /* set up the fs stucture */
+ fs.fs_ops = *ops;
+
+ /*
+ * This boldly assumes that we don't mix FS_NODEV filesystems
+ * with FS_DEV filesystems...
+ */
+ if (fs.fs_ops->fs_flags & FS_NODEV) {
+ fs.fs_dev = NULL;
+ } else {
+ if (!dev)
+ dev = device_init(disk_devno, disk_cdrom, disk_offset,
+ disk_heads, disk_sectors);
+ fs.fs_dev = dev;
+ }
+ /* invoke the fs-specific init code */
+ blk_shift = fs.fs_ops->fs_init(&fs);
+ ops++;
+ }
+ if (blk_shift < 0) {
+ printf("No valid file system found!\n");
+ while (1)
+ ;
+ }
+ this_fs = &fs;
+
+ /* initialize the cache */
+ if (fs.fs_dev && fs.fs_dev->cache_data)
+ cache_init(fs.fs_dev, blk_shift);
+
+ if (fs.fs_ops->iget_current)
+ this_inode = fs.fs_ops->iget_current();
+}
diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c
new file mode 100644
index 00000000..85aa56e8
--- /dev/null
+++ b/core/fs/btrfs/btrfs.c
@@ -0,0 +1,647 @@
+/*
+ * btrfs.c -- readonly btrfs support for syslinux
+ * Some data structures are derivated from btrfs-tools-0.19 ctree.h
+ * Copyright 2009 Intel Corporation; author: alek.du@intel.com
+ *
+ * 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.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include "btrfs.h"
+
+/* compare function used for bin_search */
+typedef int (*cmp_func)(void *ptr1, void *ptr2);
+
+/* simple but useful bin search, used for chunk search and btree search */
+static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func,
+ int min, int max, int *slot)
+{
+ int low = min;
+ int high = max;
+ int mid;
+ int ret;
+ unsigned long offset;
+ void *item;
+
+ while (low < high) {
+ mid = (low + high) / 2;
+ offset = mid * item_size;
+
+ item = ptr + offset;
+ ret = func(item, cmp_item);
+
+ if (ret < 0)
+ low = mid + 1;
+ else if (ret > 0)
+ high = mid;
+ else {
+ *slot = mid;
+ return 0;
+ }
+ }
+ *slot = low;
+ return 1;
+}
+
+struct open_file_t {
+ u64 devid; /* always 1 if allocated, reserved for multi disks */
+ u64 bytenr; /* start offset in devid */
+ u64 pos; /* current offset in file */
+};
+
+static struct open_file_t Files[MAX_OPEN];
+static int cache_ready;
+static struct fs_info *fs;
+static struct btrfs_chunk_map chunk_map;
+static struct btrfs_super_block sb;
+/* used for small chunk read for btrfs_read */
+#define RAW_BUF_SIZE 4096
+static u8 raw_buf[RAW_BUF_SIZE];
+static u64 fs_tree;
+
+static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1,
+ struct btrfs_chunk_map_item *m2)
+{
+ if (m1->logical > m2->logical)
+ return 1;
+ if (m1->logical < m2->logical)
+ return -1;
+ return 0;
+}
+
+/* insert a new chunk mapping item */
+static void insert_map(struct btrfs_chunk_map_item *item)
+{
+ int ret;
+ int slot;
+ int i;
+
+ ret = bin_search(chunk_map.map, sizeof(*item), item,
+ (cmp_func)btrfs_comp_chunk_map, 0,
+ chunk_map.cur_length, &slot);
+ if (ret == 0)/* already in map */
+ return;
+ if (chunk_map.cur_length == BTRFS_MAX_CHUNK_ENTRIES) {
+ /* should be impossible */
+ printf("too many chunk items\n");
+ return;
+ }
+ for (i = chunk_map.cur_length; i > slot; i--)
+ chunk_map.map[i] = chunk_map.map[i-1];
+ chunk_map.map[slot] = *item;
+ chunk_map.cur_length++;
+}
+
+/*
+ * from sys_chunk_array or chunk_tree, we can convert a logical address to
+ * a physical address we can not support multi device case yet
+ */
+static u64 logical_physical(u64 logical)
+{
+ struct btrfs_chunk_map_item item;
+ int slot, ret;
+
+ item.logical = logical;
+ ret = bin_search(chunk_map.map, sizeof(*chunk_map.map), &item,
+ (cmp_func)btrfs_comp_chunk_map, 0,
+ chunk_map.cur_length, &slot);
+ if (ret == 0)
+ slot++;
+ else if (slot == 0)
+ return -1;
+ if (logical >=
+ chunk_map.map[slot-1].logical + chunk_map.map[slot-1].length)
+ return -1;
+ return chunk_map.map[slot-1].physical + logical -
+ chunk_map.map[slot-1].logical;
+}
+
+/* raw read from disk, offset and count are bytes */
+static int raw_read(char *buf, u64 offset, u64 count)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ size_t max = RAW_BUF_SIZE >> disk->sector_shift;
+ size_t off, cnt, done, total;
+ sector_t sec;
+
+ total = count;
+ while (count > 0) {
+ sec = offset >> disk->sector_shift;
+ off = offset - (sec << disk->sector_shift);
+ done = disk->rdwr_sectors(disk, raw_buf, sec, max, 0);
+ if (done == 0)/* no data */
+ break;
+ cnt = (done << disk->sector_shift) - off;
+ if (cnt > count)
+ cnt = count;
+ memcpy(buf, raw_buf + off, cnt);
+ count -= cnt;
+ buf += cnt;
+ offset += cnt;
+ if (done != max)/* no enough sectors */
+ break;
+ }
+ return total - count;
+}
+
+/* cache read from disk, offset and count are bytes */
+static int cache_read(char *buf, u64 offset, u64 count)
+{
+ size_t block_size = fs->fs_dev->cache_block_size;
+ struct cache_struct *cs;
+ size_t off, cnt, total;
+ block_t block;
+
+ total = count;
+ while (count > 0) {
+ block = offset / block_size;
+ off = offset % block_size;
+ cs = get_cache_block(fs->fs_dev, block);
+ if (cs == NULL)/* no data */
+ break;
+ cnt = block_size - off;
+ if (cnt > count)
+ cnt = count;
+ memcpy(buf, cs->data + off, cnt);
+ count -= cnt;
+ buf += cnt;
+ offset += cnt;
+ }
+ return total - count;
+}
+
+static int btrfs_read(char *buf, u64 offset, u64 count)
+{
+ if (cache_ready)
+ return cache_read(buf, offset, count);
+ return raw_read(buf, offset, count);
+}
+
+/* btrfs has several super block mirrors, need to calculate their location */
+static inline u64 btrfs_sb_offset(int mirror)
+{
+ u64 start = 16 * 1024;
+ if (mirror)
+ return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror);
+ return BTRFS_SUPER_INFO_OFFSET;
+}
+
+/* find the most recent super block */
+static void btrfs_read_super_block()
+{
+ int i;
+ int ret;
+ u8 fsid[BTRFS_FSID_SIZE];
+ u64 offset;
+ u64 transid = 0;
+ struct btrfs_super_block buf;
+
+ /* find most recent super block */
+ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) {
+ offset = btrfs_sb_offset(i);
+ ret = btrfs_read((char *)&buf, offset, sizeof(buf));
+ if (ret < sizeof(buf))
+ break;
+
+ if (buf.bytenr != offset ||
+ strncmp((char *)(&buf.magic), BTRFS_MAGIC,
+ sizeof(buf.magic)))
+ continue;
+
+ if (i == 0)
+ memcpy(fsid, buf.fsid, sizeof(fsid));
+ else if (memcmp(fsid, buf.fsid, sizeof(fsid)))
+ continue;
+
+ if (buf.generation > transid) {
+ memcpy(&sb, &buf, sizeof(sb));
+ transid = buf.generation;
+ }
+ }
+}
+
+static inline unsigned long btrfs_chunk_item_size(int num_stripes)
+{
+ return sizeof(struct btrfs_chunk) +
+ sizeof(struct btrfs_stripe) * (num_stripes - 1);
+}
+
+static void clear_path(struct btrfs_path *path)
+{
+ memset(path, 0, sizeof(*path));
+}
+
+static int btrfs_comp_keys(struct btrfs_disk_key *k1, struct btrfs_disk_key *k2)
+{
+ if (k1->objectid > k2->objectid)
+ return 1;
+ if (k1->objectid < k2->objectid)
+ return -1;
+ if (k1->type > k2->type)
+ return 1;
+ if (k1->type < k2->type)
+ return -1;
+ if (k1->offset > k2->offset)
+ return 1;
+ if (k1->offset < k2->offset)
+ return -1;
+ return 0;
+}
+
+/* seach tree directly on disk ... */
+static int search_tree(u64 loffset, struct btrfs_disk_key *key,
+ struct btrfs_path *path)
+{
+ u8 buf[BTRFS_MAX_LEAF_SIZE];
+ struct btrfs_header *header = (struct btrfs_header *)buf;
+ struct btrfs_node *node = (struct btrfs_node *)buf;
+ struct btrfs_leaf *leaf = (struct btrfs_leaf *)buf;
+ int slot, ret;
+ u64 offset;
+
+ offset = logical_physical(loffset);
+ btrfs_read((char *)header, offset, sizeof(*header));
+ if (header->level) {/*node*/
+ btrfs_read((char *)&node->ptrs[0], offset + sizeof(*header),
+ sb.nodesize - sizeof(*header));
+ path->itemsnr[header->level] = header->nritems;
+ path->offsets[header->level] = loffset;
+ ret = bin_search(&node->ptrs[0], sizeof(struct btrfs_key_ptr),
+ key, (cmp_func)btrfs_comp_keys,
+ path->slots[header->level], header->nritems, &slot);
+ if (ret && slot > path->slots[header->level])
+ slot--;
+ path->slots[header->level] = slot;
+ ret = search_tree(node->ptrs[slot].blockptr, key, path);
+ } else {/*leaf*/
+ btrfs_read((char *)&leaf->items, offset + sizeof(*header),
+ sb.leafsize - sizeof(*header));
+ path->itemsnr[header->level] = header->nritems;
+ path->offsets[0] = loffset;
+ ret = bin_search(&leaf->items[0], sizeof(struct btrfs_item),
+ key, (cmp_func)btrfs_comp_keys, path->slots[0],
+ header->nritems, &slot);
+ if (ret && slot > path->slots[header->level])
+ slot--;
+ path->slots[0] = slot;
+ path->item = leaf->items[slot];
+ btrfs_read((char *)&path->data,
+ offset + sizeof(*header) + leaf->items[slot].offset,
+ leaf->items[slot].size);
+ }
+ return ret;
+}
+
+/* return 0 if leaf found */
+static int next_leaf(struct btrfs_disk_key *key, struct btrfs_path *path)
+{
+ int slot;
+ int level = 1;
+
+ while (level < BTRFS_MAX_LEVEL) {
+ if (!path->itemsnr[level]) /* no more nodes */
+ return 1;
+ slot = path->slots[level] + 1;
+ if (slot >= path->itemsnr[level]) {
+ level++;
+ continue;;
+ }
+ path->slots[level] = slot;
+ path->slots[level-1] = 0; /* reset low level slots info */
+ search_tree(path->offsets[level], key, path);
+ break;
+ }
+ if (level == BTRFS_MAX_LEVEL)
+ return 1;
+ return 0;
+}
+
+/* return 0 if slot found */
+static int next_slot(struct btrfs_disk_key *key, struct btrfs_path *path)
+{
+ int slot;
+
+ if (!path->itemsnr[0])
+ return 1;
+ slot = path->slots[0] + 1;
+ if (slot >= path->itemsnr[0])
+ return 1;
+ path->slots[0] = slot;
+ search_tree(path->offsets[0], key, path);
+ return 0;
+}
+
+/*
+ * read chunk_array in super block
+ */
+static void btrfs_read_sys_chunk_array()
+{
+ struct btrfs_chunk_map_item item;
+ struct btrfs_disk_key *key;
+ struct btrfs_chunk *chunk;
+ int cur;
+
+ /* read chunk array in superblock */
+ cur = 0;
+ while (cur < sb.sys_chunk_array_size) {
+ key = (struct btrfs_disk_key *)(sb.sys_chunk_array + cur);
+ cur += sizeof(*key);
+ chunk = (struct btrfs_chunk *)(sb.sys_chunk_array + cur);
+ cur += btrfs_chunk_item_size(chunk->num_stripes);
+ /* insert to mapping table, ignore multi stripes */
+ item.logical = key->offset;
+ item.length = chunk->length;
+ item.devid = chunk->stripe.devid;
+ item.physical = chunk->stripe.offset;/*ignore other stripes */
+ insert_map(&item);
+ }
+}
+
+/* read chunk items from chunk_tree and insert them to chunk map */
+static void btrfs_read_chunk_tree()
+{
+ struct btrfs_disk_key search_key;
+ struct btrfs_chunk *chunk;
+ struct btrfs_chunk_map_item item;
+ struct btrfs_path path;
+
+ if (!(sb.flags & BTRFS_SUPER_FLAG_METADUMP)) {
+ if (sb.num_devices > 1)
+ printf("warning: only support single device btrfs\n");
+ /* read chunk from chunk_tree */
+ search_key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
+ search_key.type = BTRFS_CHUNK_ITEM_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ search_tree(sb.chunk_root, &search_key, &path);
+ do {
+ do {
+ if (path.item.key.objectid !=
+ BTRFS_FIRST_CHUNK_TREE_OBJECTID)
+ break;
+ chunk = (struct btrfs_chunk *)(path.data);
+ /* insert to mapping table, ignore stripes */
+ item.logical = path.item.key.offset;
+ item.length = chunk->length;
+ item.devid = chunk->stripe.devid;
+ item.physical = chunk->stripe.offset;
+ insert_map(&item);
+ } while (!next_slot(&search_key, &path));
+ if (path.item.key.objectid !=
+ BTRFS_FIRST_CHUNK_TREE_OBJECTID)
+ break;
+ } while (!next_leaf(&search_key, &path));
+ }
+}
+
+static inline u64 btrfs_name_hash(const char *name, int len)
+{
+ return btrfs_crc32c((u32)~1, name, len);
+}
+
+/* search a file with full path in fs_tree, do not support ../ ./ style path */
+static int btrfs_search_fs_tree(const char *fullpath, u64 *offset,
+ u64 *size, u8 *type)
+{
+ char name[256];
+ char *tmp = name;
+ u64 objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
+ int ret;
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_dir_item dir_item;
+ struct btrfs_inode_item inode_item;
+ struct btrfs_file_extent_item extent_item;
+
+ *tmp = '\0';
+ while (1) {
+ char c = *(fullpath++);
+
+ *(tmp++) = c;
+ if (!c)
+ break;
+ if (c == '/') {
+ *(tmp-1) = '\0';
+ if (strlen(name)) {/* a "real" dir */
+ search_key.objectid = objectid;
+ search_key.type = BTRFS_DIR_ITEM_KEY;
+ search_key.offset =
+ btrfs_name_hash(name, strlen(name));
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return ret; /* not found */
+ dir_item = *(struct btrfs_dir_item *)path.data;
+ /* found the name but it is not a dir ? */
+ if (dir_item.type != BTRFS_FT_DIR) {
+ printf("%s is not a dir\n", name);
+ return -1;
+ }
+ objectid = dir_item.location.objectid;
+ }
+ tmp = name;
+ *tmp = '\0';
+ }
+ }
+ /* get file dir_item */
+ if (!strlen(name))/* no file part */
+ return -1;
+ search_key.objectid = objectid;
+ search_key.type = BTRFS_DIR_ITEM_KEY;
+ search_key.offset = btrfs_name_hash(name, strlen(name));
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return ret; /* not found */
+ dir_item = *(struct btrfs_dir_item *)path.data;
+ *type = dir_item.type;
+ /* found the name but it is not a file ? */
+ if (*type != BTRFS_FT_REG_FILE && *type != BTRFS_FT_SYMLINK) {
+ printf("%s is not a file\n", name);
+ return -1;
+ }
+
+ /* get inode */
+ search_key = dir_item.location;
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return ret; /* not found */
+ inode_item = *(struct btrfs_inode_item *)path.data;
+
+ /* get file_extent_item */
+ search_key.objectid = dir_item.location.objectid;
+ search_key.type = BTRFS_EXTENT_DATA_KEY;
+ search_key.offset = 0;
+ clear_path(&path);
+ ret = search_tree(fs_tree, &search_key, &path);
+ if (ret)
+ return ret; /* not found */
+ extent_item = *(struct btrfs_file_extent_item *)path.data;
+ *size = inode_item.size;
+ if (extent_item.type == BTRFS_FILE_EXTENT_INLINE)/* inline file */
+ *offset = path.offsets[0] + sizeof(struct btrfs_header)
+ + path.item.offset
+ + offsetof(struct btrfs_file_extent_item, disk_bytenr);
+ else
+ *offset = extent_item.disk_bytenr;
+
+ return 0;
+}
+
+static struct open_file_t *alloc_file(void)
+{
+ struct open_file_t *file = Files;
+ int i;
+
+ for (i = 0; i < MAX_OPEN; i++) {
+ if (file->devid == 0) /* found it */
+ return file;
+ file++;
+ }
+
+ return NULL; /* not found */
+}
+
+static inline void close_pvt(struct open_file_t *of)
+{
+ of->devid = 0;
+}
+
+static void btrfs_close_file(struct file *file)
+{
+ close_pvt(file->open_file);
+}
+
+static void btrfs_searchdir(char *filename, struct file *file)
+{
+ struct open_file_t *open_file;
+ u64 offset, size;
+ char name[FILENAME_MAX];
+ char *fname = filename;
+ u8 type;
+ int ret;
+
+ file->open_file = NULL;
+ file->file_len = 0;
+ do {
+ ret = btrfs_search_fs_tree(fname, &offset, &size, &type);
+ if (ret)
+ break;
+ if (type == BTRFS_FT_SYMLINK) {
+ btrfs_read(name, logical_physical(offset), size);
+ name[size] = '\0';
+ fname = name;
+ continue;
+ }
+ open_file = alloc_file();
+ file->open_file = (void *)open_file;
+ if (open_file) {
+ /* we may support multi devices later on */
+ open_file->devid = 1;
+ open_file->bytenr = offset;
+ open_file->pos = 0;
+ file->file_len = size;
+ }
+ break;
+ } while (1);
+}
+
+/* Load the config file, return 1 if failed, or 0 */
+static int btrfs_load_config(void)
+{
+ char *config_name = "extlinux.conf";/* use same config name as ext2 too? */
+ com32sys_t regs;
+
+ strcpy(ConfigName, config_name);
+ *(uint16_t *)CurrentDirName = ROOT_DIR_WORD;
+
+ memset(&regs, 0, sizeof regs);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+
+ return !!(regs.eflags.l & EFLAGS_ZF);
+}
+
+static uint32_t btrfs_getfssec(struct file *gfile, char *buf, int sectors,
+ bool *have_more)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ struct open_file_t *file = gfile->open_file;
+ u32 sec_shift = fs->fs_dev->disk->sector_shift;
+ u32 phy = logical_physical(file->bytenr + file->pos);
+ u32 sec = phy >> sec_shift;
+ u32 off = phy - (sec << sec_shift);
+ u32 remain = gfile->file_len - file->pos;
+ u32 remain_sec = (remain + (1 << sec_shift) - 1) >> sec_shift;
+ u32 size;
+
+ if (sectors > remain_sec)
+ sectors = remain_sec;
+ /* btrfs extent is continus */
+ disk->rdwr_sectors(disk, buf, sec, sectors, 0);
+ size = sectors << sec_shift;
+ if (size > remain)
+ size = remain;
+ file->pos += size;
+ *have_more = remain - size;
+
+ if (off)/* inline file is not started with sector boundary */
+ memcpy(buf, buf + off, size);
+
+ return size;
+}
+
+static void btrfs_get_fs_tree(void)
+{
+ struct btrfs_disk_key search_key;
+ struct btrfs_path path;
+ struct btrfs_root_item *tree;
+
+ /* find fs_tree from tree_root */
+ search_key.objectid = BTRFS_FS_TREE_OBJECTID;
+ search_key.type = BTRFS_ROOT_ITEM_KEY;
+ search_key.offset = -1;
+ clear_path(&path);
+ search_tree(sb.root, &search_key, &path);
+ tree = (struct btrfs_root_item *)path.data;
+ fs_tree = tree->bytenr;
+}
+
+/* init. the fs meta data, return the block size shift bits. */
+static int btrfs_fs_init(struct fs_info *_fs)
+{
+ btrfs_init_crc32c();
+
+ fs = _fs;
+ btrfs_read_super_block();
+ if (strncmp((char *)(&sb.magic), BTRFS_MAGIC, sizeof(sb.magic)))
+ return -1;
+ btrfs_read_sys_chunk_array();
+ btrfs_read_chunk_tree();
+ btrfs_get_fs_tree();
+ cache_ready = 1;
+ return BTRFS_BLOCK_SHIFT;/* to determine cache size */
+}
+
+const struct fs_ops btrfs_fs_ops = {
+ .fs_name = "btrfs",
+ .fs_flags = 0,
+ .fs_init = btrfs_fs_init,
+ .searchdir = btrfs_searchdir,
+ .getfssec = btrfs_getfssec,
+ .close_file = btrfs_close_file,
+ .mangle_name = generic_mangle_name,
+ .unmangle_name = generic_unmangle_name,
+ .load_config = btrfs_load_config
+};
diff --git a/core/fs/btrfs/btrfs.h b/core/fs/btrfs/btrfs.h
new file mode 100644
index 00000000..9ee90926
--- /dev/null
+++ b/core/fs/btrfs/btrfs.h
@@ -0,0 +1,275 @@
+#ifndef _BTRFS_H_
+#define _BTRFS_H_
+
+#include <stdint.h>
+#include <zconf.h>
+
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;
+typedef uint64_t u64;
+/* type that store on disk, but it is same as cpu type for i386 arch */
+typedef u16 __le16;
+typedef u32 __le32;
+typedef u64 __le64;
+
+#include "crc32c.h"
+#define btrfs_crc32c crc32c_le
+
+#define BTRFS_SUPER_INFO_OFFSET (64 * 1024)
+#define BTRFS_SUPER_INFO_SIZE 4096
+#define BTRFS_MAX_LEAF_SIZE 4096
+#define BTRFS_BLOCK_SHIFT 12
+
+#define BTRFS_SUPER_MIRROR_MAX 3
+#define BTRFS_SUPER_MIRROR_SHIFT 12
+#define BTRFS_CSUM_SIZE 32
+#define BTRFS_FSID_SIZE 16
+#define BTRFS_LABEL_SIZE 256
+#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048
+#define BTRFS_UUID_SIZE 16
+
+#define BTRFS_MAGIC "_BHRfS_M"
+
+#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33)
+
+#define BTRFS_DEV_ITEM_KEY 216
+#define BTRFS_CHUNK_ITEM_KEY 228
+#define BTRFS_ROOT_ITEM_KEY 132
+#define BTRFS_EXTENT_DATA_KEY 108
+#define BTRFS_DIR_ITEM_KEY 84
+
+#define BTRFS_EXTENT_TREE_OBJECTID 2ULL
+#define BTRFS_FS_TREE_OBJECTID 5ULL
+
+#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL
+
+#define BTRFS_FILE_EXTENT_INLINE 0
+#define BTRFS_FILE_EXTENT_REG 1
+#define BTRFS_FILE_EXTENT_PREALLOC 2
+
+#define BTRFS_MAX_LEVEL 8
+#define BTRFS_MAX_CHUNK_ENTRIES 256
+
+#define BTRFS_FT_REG_FILE 1
+#define BTRFS_FT_DIR 2
+#define BTRFS_FT_SYMLINK 7
+
+#define ROOT_DIR_WORD 0x002f
+
+struct btrfs_dev_item {
+ __le64 devid;
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le32 io_align;
+ __le32 io_width;
+ __le32 sector_size;
+ __le64 type;
+ __le64 generation;
+ __le64 start_offset;
+ __le32 dev_group;
+ u8 seek_speed;
+ u8 bandwidth;
+ u8 uuid[BTRFS_UUID_SIZE];
+ u8 fsid[BTRFS_UUID_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_super_block {
+ u8 csum[BTRFS_CSUM_SIZE];
+ /* the first 3 fields must match struct btrfs_header */
+ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+ __le64 bytenr; /* this block number */
+ __le64 flags;
+
+ /* allowed to be different from the btrfs_header from here own down */
+ __le64 magic;
+ __le64 generation;
+ __le64 root;
+ __le64 chunk_root;
+ __le64 log_root;
+
+ /* this will help find the new super based on the log root */
+ __le64 log_root_transid;
+ __le64 total_bytes;
+ __le64 bytes_used;
+ __le64 root_dir_objectid;
+ __le64 num_devices;
+ __le32 sectorsize;
+ __le32 nodesize;
+ __le32 leafsize;
+ __le32 stripesize;
+ __le32 sys_chunk_array_size;
+ __le64 chunk_root_generation;
+ __le64 compat_flags;
+ __le64 compat_ro_flags;
+ __le64 incompat_flags;
+ __le16 csum_type;
+ u8 root_level;
+ u8 chunk_root_level;
+ u8 log_root_level;
+ struct btrfs_dev_item dev_item;
+
+ char label[BTRFS_LABEL_SIZE];
+
+ /* future expansion */
+ __le64 reserved[32];
+ u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_disk_key {
+ __le64 objectid;
+ u8 type;
+ __le64 offset;
+} __attribute__ ((__packed__));
+
+struct btrfs_stripe {
+ __le64 devid;
+ __le64 offset;
+ u8 dev_uuid[BTRFS_UUID_SIZE];
+} __attribute__ ((__packed__));
+
+struct btrfs_chunk {
+ __le64 length;
+ __le64 owner;
+ __le64 stripe_len;
+ __le64 type;
+ __le32 io_align;
+ __le32 io_width;
+ __le32 sector_size;
+ __le16 num_stripes;
+ __le16 sub_stripes;
+ struct btrfs_stripe stripe;
+} __attribute__ ((__packed__));
+
+struct btrfs_header {
+ /* these first four must match the super block */
+ u8 csum[BTRFS_CSUM_SIZE];
+ u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */
+ __le64 bytenr; /* which block this node is supposed to live in */
+ __le64 flags;
+
+ /* allowed to be different from the super from here on down */
+ u8 chunk_tree_uuid[BTRFS_UUID_SIZE];
+ __le64 generation;
+ __le64 owner;
+ __le32 nritems;
+ u8 level;
+} __attribute__ ((__packed__));
+
+struct btrfs_item {
+ struct btrfs_disk_key key;
+ __le32 offset;
+ __le32 size;
+} __attribute__ ((__packed__));
+
+struct btrfs_leaf {
+ struct btrfs_header header;
+ struct btrfs_item items[];
+} __attribute__ ((__packed__));
+
+struct btrfs_key_ptr {
+ struct btrfs_disk_key key;
+ __le64 blockptr;
+ __le64 generation;
+} __attribute__ ((__packed__));
+
+struct btrfs_node {
+ struct btrfs_header header;
+ struct btrfs_key_ptr ptrs[];
+} __attribute__ ((__packed__));
+
+/* remember how we get to a node/leaf */
+struct btrfs_path {
+ u64 offsets[BTRFS_MAX_LEVEL];
+ int itemsnr[BTRFS_MAX_LEVEL];
+ int slots[BTRFS_MAX_LEVEL];
+ /* remember last slot's item and data */
+ struct btrfs_item item;
+ u8 data[BTRFS_MAX_LEAF_SIZE];
+};
+
+/* store logical offset to physical offset mapping */
+struct btrfs_chunk_map_item {
+ u64 logical;
+ u64 length;
+ u64 devid;
+ u64 physical;
+};
+
+struct btrfs_chunk_map {
+ struct btrfs_chunk_map_item map[BTRFS_MAX_CHUNK_ENTRIES];
+ u32 map_length;
+ u32 cur_length;
+};
+
+struct btrfs_timespec {
+ __le64 sec;
+ __le32 nsec;
+} __attribute__ ((__packed__));
+
+struct btrfs_inode_item {
+ /* nfs style generation number */
+ __le64 generation;
+ /* transid that last touched this inode */
+ __le64 transid;
+ __le64 size;
+ __le64 nbytes;
+ __le64 block_group;
+ __le32 nlink;
+ __le32 uid;
+ __le32 gid;
+ __le32 mode;
+ __le64 rdev;
+ __le64 flags;
+
+ /* modification sequence number for NFS */
+ __le64 sequence;
+
+ /*
+ * a little future expansion, for more than this we can
+ * just grow the inode item and version it
+ */
+ __le64 reserved[4];
+ struct btrfs_timespec atime;
+ struct btrfs_timespec ctime;
+ struct btrfs_timespec mtime;
+ struct btrfs_timespec otime;
+} __attribute__ ((__packed__));
+
+struct btrfs_root_item {
+ struct btrfs_inode_item inode;
+ __le64 generation;
+ __le64 root_dirid;
+ __le64 bytenr;
+ __le64 byte_limit;
+ __le64 bytes_used;
+ __le64 last_snapshot;
+ __le64 flags;
+ __le32 refs;
+ struct btrfs_disk_key drop_progress;
+ u8 drop_level;
+ u8 level;
+} __attribute__ ((__packed__));
+
+struct btrfs_dir_item {
+ struct btrfs_disk_key location;
+ __le64 transid;
+ __le16 data_len;
+ __le16 name_len;
+ u8 type;
+} __attribute__ ((__packed__));
+
+struct btrfs_file_extent_item {
+ __le64 generation;
+ __le64 ram_bytes;
+ u8 compression;
+ u8 encryption;
+ __le16 other_encoding; /* spare for later use */
+ u8 type;
+ __le64 disk_bytenr;
+ __le64 disk_num_bytes;
+ __le64 offset;
+ __le64 num_bytes;
+} __attribute__ ((__packed__));
+
+#endif
diff --git a/core/fs/btrfs/crc32c.h b/core/fs/btrfs/crc32c.h
new file mode 100644
index 00000000..2c317384
--- /dev/null
+++ b/core/fs/btrfs/crc32c.h
@@ -0,0 +1,50 @@
+/*
+ * Copied from Linux kernel crypto/crc32c.c
+ * Copyright (c) 2004 Cisco Systems, Inc.
+ * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
+ *
+ * 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; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+/*
+ * This is the CRC-32C table
+ * Generated with:
+ * width = 32 bits
+ * poly = 0x1EDC6F41
+ * reflect input bytes = true
+ * reflect output bytes = true
+ */
+
+static u32 crc32c_table[256];
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static inline u32 crc32c_le(u32 crc, const char *data, size_t length)
+{
+ while (length--)
+ crc = crc32c_table[(u8)(crc ^ *data++)] ^ (crc >> 8);
+
+ return crc;
+}
+
+static inline void btrfs_init_crc32c(void)
+{
+ int i, j;
+ u32 v;
+ const u32 poly = 0x82F63B78; /* Bit-reflected CRC32C polynomial */
+
+ for (i = 0; i < 256; i++) {
+ v = i;
+ for (j = 0; j < 8; j++) {
+ v = (v >> 1) ^ ((v & 1) ? poly : 0);
+ }
+ crc32c_table[i] = v;
+ }
+}
diff --git a/core/fs/ext2/bmap.c b/core/fs/ext2/bmap.c
new file mode 100644
index 00000000..e38bcd2c
--- /dev/null
+++ b/core/fs/ext2/bmap.c
@@ -0,0 +1,185 @@
+/*
+ * The logical block -> physical block routine.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <fs.h>
+#include <disk.h>
+#include <cache.h>
+#include "ext2_fs.h"
+
+
+static struct ext4_extent_header *
+ext4_find_leaf(struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
+{
+ struct ext4_extent_idx *index;
+ struct cache_struct *cs;
+ block_t blk;
+ int i;
+
+ while (1) {
+ if (eh->eh_magic != EXT4_EXT_MAGIC)
+ return NULL;
+ if (eh->eh_depth == 0)
+ return eh;
+
+ index = EXT4_FIRST_INDEX(eh);
+ for (i = 0; i < (int)eh->eh_entries; i++) {
+ if (block < index[i].ei_block)
+ break;
+ }
+ if (--i < 0)
+ return NULL;
+
+ blk = index[i].ei_leaf_hi;
+ blk = (blk << 32) + index[i].ei_leaf_lo;
+ cs = get_cache_block(fs->fs_dev, blk);
+ eh = (struct ext4_extent_header *)cs->data;
+ }
+}
+
+/* handle the ext4 extents to get the phsical block number */
+static uint64_t bmap_extent(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ struct ext4_extent_header *leaf;
+ struct ext4_extent *ext;
+ int i;
+ block_t start;
+
+ leaf = ext4_find_leaf(fs, (struct ext4_extent_header *)inode->data, block);
+ if (!leaf) {
+ printf("ERROR, extent leaf not found\n");
+ return 0;
+ }
+
+ ext = EXT4_FIRST_EXTENT(leaf);
+ for (i = 0; i < leaf->eh_entries; i++) {
+ if (block < ext[i].ee_block)
+ break;
+ }
+ if (--i < 0) {
+ printf("ERROR, not find the right block\n");
+ return 0;
+ }
+
+ /* got it */
+ block -= ext[i].ee_block;
+ if (block >= ext[i].ee_len)
+ return 0;
+ start = ext[i].ee_start_hi;
+ start = (start << 32) + ext[i].ee_start_lo;
+
+ return start + block;
+}
+
+
+/*
+ * handle the traditional block map, like indirect, double indirect
+ * and triple indirect
+ */
+static unsigned int bmap_traditional(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t block)
+{
+ int addr_per_block = BLOCK_SIZE(fs) >> 2;
+ uint32_t direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = addr_per_block,
+ double_blocks = addr_per_block * addr_per_block,
+ triple_blocks = double_blocks * addr_per_block;
+ struct cache_struct *cs;
+
+ /* direct blocks */
+ if (block < direct_blocks)
+ return inode->data[block];
+
+ /* indirect blocks */
+ block -= direct_blocks;
+ if (block < indirect_blocks) {
+ block_t ind_block = inode->data[EXT2_IND_BLOCK];
+
+ if (!ind_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, ind_block);
+
+ return ((uint32_t *)cs->data)[block];
+ }
+
+
+ /* double indirect blocks */
+ block -= indirect_blocks;
+ if (block < double_blocks) {
+ block_t dou_block = inode->data[EXT2_DIND_BLOCK];
+
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ dou_block = ((uint32_t *)cs->data)[block / indirect_blocks];
+ if (!dou_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, dou_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* triple indirect block */
+ block -= double_blocks;
+ if (block < triple_blocks) {
+ block_t tri_block = inode->data[EXT2_TIND_BLOCK];
+
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = ((uint32_t *)cs->data)[block / double_blocks];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ tri_block = (block / addr_per_block) % addr_per_block;
+ tri_block = ((uint32_t *)cs->data)[tri_block];
+ if (!tri_block)
+ return 0;
+ cs = get_cache_block(fs->fs_dev, tri_block);
+
+ return ((uint32_t *)cs->data)[block % addr_per_block];
+ }
+
+
+ /* File too big, can not handle */
+ printf("ERROR, file too big\n");
+ return 0;
+}
+
+
+/**
+ * Map the logical block to physic block where the file data stores.
+ * In EXT4, there are two ways to handle the map process, extents and indirect.
+ * EXT4 uses a inode flag to mark extent file and indirect block file.
+ *
+ * @fs: the fs_info structure.
+ * @inode: the inode structure.
+ * @block: the logical blcok needed to be maped.
+ * @retrun: the physic block number.
+ *
+ */
+block_t bmap(struct fs_info *fs, struct inode * inode, int block)
+{
+ block_t ret;
+
+ if (block < 0)
+ return 0;
+
+ if (inode->flags & EXT4_EXTENTS_FLAG)
+ ret = bmap_extent(fs, inode, block);
+ else
+ ret = bmap_traditional(fs, inode, block);
+
+ return ret;
+}
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
new file mode 100644
index 00000000..9d4d9ec5
--- /dev/null
+++ b/core/fs/ext2/ext2.c
@@ -0,0 +1,495 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include "ext2_fs.h"
+
+/*
+ * just like the function strcpy(), except it returns non-zero if overflow.
+ *
+ */
+static int strecpy(char *dst, const char *src, char *end)
+{
+ while (*src != '\0')
+ *dst++ = *src++;
+ *dst = '\0';
+
+ if (dst > end)
+ return 1;
+ else
+ return 0;
+}
+
+static void ext2_close_file(struct file *file)
+{
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
+}
+
+/*
+ * get the group's descriptor of group_num
+ */
+struct ext2_group_desc * ext2_get_group_desc(uint32_t group_num)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(this_fs);
+
+ if (group_num >= sbi->s_groups_count) {
+ printf ("ext2_get_group_desc"
+ "block_group >= groups_count - "
+ "block_group = %d, groups_count = %d",
+ group_num, sbi->s_groups_count);
+
+ return NULL;
+ }
+
+ return sbi->s_group_desc[group_num];
+}
+
+
+
+/**
+ * linsector:
+ *
+ * Convert a linear sector index in a file to linear sector number
+ *
+ * well, alought this function converts a linear sector number to
+ * physic sector number, it uses block cache in the implemention.
+ *
+ * @param: lin_sector, the lineral sector index
+ *
+ * @return: physic sector number
+ */
+static sector_t linsector(struct fs_info *fs,
+ struct inode *inode,
+ uint32_t lin_sector)
+{
+ int blk_bits = fs->block_shift - fs->sector_shift;
+ block_t block = bmap(fs, inode, lin_sector >> blk_bits);
+
+ return (block << blk_bits) + (lin_sector & ((1 << blk_bits) - 1));
+}
+
+
+/**
+ * getlinsec_ext:
+ *
+ * same as getlinsec, except load any sector from the zero
+ * block as all zeros; use to load any data derived from
+ * n ext2 block pointer, i.e. anything *except the superblock
+ *
+ */
+static void getlinsec_ext(struct fs_info *fs, char *buf,
+ sector_t sector, int sector_cnt)
+{
+ int ext_cnt = 0;
+ int sec_per_block = 1 << (fs->block_shift - fs->sector_shift);
+ struct disk *disk = fs->fs_dev->disk;
+
+ if (sector < sec_per_block) {
+ ext_cnt = sec_per_block - sector;
+ memset(buf, 0, ext_cnt << fs->sector_shift);
+ buf += ext_cnt << fs->sector_shift;
+ }
+
+ sector += ext_cnt;
+ sector_cnt -= ext_cnt;
+ disk->rdwr_sectors(disk, buf, sector, sector_cnt, 0);
+}
+
+/*
+ * Get multiple sectors from a file
+ *
+ * Alought we have made the buffer data based on block size,
+ * we use sector for implemention; because reading multiple
+ * sectors (then can be multiple blocks) is what the function
+ * do. So, let it be based on sectors.
+ *
+ */
+static uint32_t ext2_getfssec(struct file *file, char *buf,
+ int sectors, bool *have_more)
+{
+ struct inode *inode = file->inode;
+ struct fs_info *fs = file->fs;
+ int sector_left, next_sector, sector_idx;
+ int frag_start, con_sec_cnt;
+ int bytes_read = sectors << fs->sector_shift;
+ uint32_t bytesleft = inode->size - file->offset;
+
+ sector_left = (bytesleft + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
+ if (sectors > sector_left)
+ sectors = sector_left;
+
+ sector_idx = file->offset >> fs->sector_shift;
+ while (sectors) {
+ /*
+ * get the frament
+ */
+ next_sector = frag_start = linsector(fs, inode, sector_idx);
+ con_sec_cnt = 0;
+
+ /* get the consective sectors count */
+ do {
+ con_sec_cnt ++;
+ sectors --;
+ if (sectors <= 0)
+ break;
+
+ /* if sectors >= the sectors left in the 64K block, break and read */
+ if (sectors >= (((~(uint32_t)buf&0xffff)|((uint32_t)buf&0xffff0000)) + 1))
+ break;
+
+ sector_idx ++;
+ next_sector ++;
+ } while (next_sector == linsector(fs, inode, sector_idx));
+
+#if 0
+ printf("You are reading data stored at sector --0x%x--0x%x\n",
+ frag_start, frag_start + con_sec_cnt -1);
+#endif
+ getlinsec_ext(fs, buf, frag_start, con_sec_cnt);
+ buf += con_sec_cnt << fs->sector_shift;
+ } while(sectors);
+
+ if (bytes_read >= bytesleft) {
+ bytes_read = bytesleft;
+ *have_more = 0;
+ } else {
+ *have_more = 1;
+ }
+ file->offset += bytes_read;
+
+ return bytes_read;
+}
+
+/*
+ * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
+ */
+static inline int ext2_match_entry (const char * const name,
+ struct ext2_dir_entry * de)
+{
+ if (!de->d_inode)
+ return 0;
+ if (strlen(name) != de->d_name_len)
+ return 0;
+ return !strncmp(name, de->d_name, de->d_name_len);
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext2_dir_entry *ext2_next_entry(struct ext2_dir_entry *p)
+{
+ return (struct ext2_dir_entry *)((char*)p + p->d_rec_len);
+}
+
+/*
+ * find a dir entry, return it if found, or return NULL.
+ */
+static struct ext2_dir_entry *
+ext2_find_entry(struct fs_info *fs, struct inode *inode, char *dname)
+{
+ int index = 0;
+ block_t block;
+ uint32_t i = 0;
+ struct ext2_dir_entry *de;
+ struct cache_struct *cs;
+
+ if (!(block = bmap(fs, inode, index++)))
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)cs->data;
+
+ while(i < (int)inode->size) {
+ if (ext2_match_entry(dname, de))
+ return de;
+ i += de->d_rec_len;
+ if (i >= (int)inode->size)
+ break;
+ if ((char *)de >= (char *)cs->data + BLOCK_SIZE(fs)) {
+ if (!(block = bmap(fs, inode, index++)))
+ break;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)cs->data;
+ continue;
+ }
+
+ de = ext2_next_entry(de);
+ }
+
+ return NULL;
+}
+
+static struct ext2_inode * get_inode(int inr)
+{
+ struct ext2_group_desc *desc;
+ struct cache_struct *cs;
+ uint32_t inode_group, inode_offset;
+ uint32_t block_num, block_off;
+
+ inr--;
+ inode_group = inr / EXT2_INODES_PER_GROUP(this_fs);
+ inode_offset = inr % EXT2_INODES_PER_GROUP(this_fs);
+ desc = ext2_get_group_desc (inode_group);
+ if (!desc)
+ return NULL;
+
+ block_num = desc->bg_inode_table +
+ inode_offset / EXT2_INODES_PER_BLOCK(this_fs);
+ block_off = inode_offset % EXT2_INODES_PER_BLOCK(this_fs);
+
+ cs = get_cache_block(this_fs->fs_dev, block_num);
+
+ return cs->data + block_off * EXT2_SB(this_fs)->s_inode_size;
+}
+
+static inline int get_inode_mode(int mode)
+{
+ mode >>= S_IFSHIFT;
+ if (mode == T_IFDIR)
+ mode = I_DIR;
+ else if (mode == T_IFLNK)
+ mode = I_SYMLINK;
+ else
+ mode = I_FILE; /* we treat others as FILE */
+ return mode;
+}
+
+static void fill_inode(struct inode *inode, struct ext2_inode *e_inode)
+{
+ inode->mode = get_inode_mode(e_inode->i_mode);
+ inode->size = e_inode->i_size;
+ inode->atime = e_inode->i_atime;
+ inode->ctime = e_inode->i_ctime;
+ inode->mtime = e_inode->i_mtime;
+ inode->dtime = e_inode->i_dtime;
+ inode->blocks = e_inode->i_blocks;
+ inode->flags = e_inode->i_flags;
+ inode->file_acl = e_inode->i_file_acl;
+
+ inode->data = malloc(EXT2_N_BLOCKS * sizeof(uint32_t *));
+ if (!inode->data) {
+ malloc_error("inode data filed");
+ return ;
+ }
+ memcpy(inode->data, e_inode->i_block, EXT2_N_BLOCKS * sizeof(uint32_t *));
+}
+
+static struct inode *ext2_iget_by_inr(uint32_t inr)
+{
+ struct ext2_inode *e_inode;
+ struct inode *inode;
+
+ e_inode = get_inode(inr);
+ if (!(inode = malloc(sizeof(*inode))))
+ return NULL;
+ fill_inode(inode, e_inode);
+ inode->ino = inr;
+
+ return inode;
+}
+
+static struct inode *ext2_iget_root()
+{
+ return ext2_iget_by_inr(EXT2_ROOT_INO);
+}
+
+static struct inode *ext2_iget_current()
+{
+ extern int CurrentDir;
+
+ return ext2_iget_by_inr(CurrentDir);
+}
+
+static struct inode *ext2_iget(char *dname, struct inode *parent)
+{
+ struct ext2_dir_entry *de;
+
+ de = ext2_find_entry(this_fs, parent, dname);
+ if (!de)
+ return NULL;
+
+ return ext2_iget_by_inr(de->d_inode);
+}
+
+
+static char * ext2_follow_symlink(struct inode *inode, const char *name_left)
+{
+ int sec_per_block = 1 << (this_fs->block_shift - this_fs->sector_shift);
+ int fast_symlink;
+ char *symlink_buf;
+ char *p;
+ struct cache_struct *cs;
+
+ symlink_buf = malloc(BLOCK_SIZE(this_fs));
+ if (!symlink_buf) {
+ malloc_error("symlink buffer");
+ return NULL;
+ }
+ fast_symlink = (inode->file_acl ? sec_per_block : 0) == inode->blocks;
+ if (fast_symlink) {
+ memcpy(symlink_buf, inode->data, inode->size);
+ } else {
+ cs = get_cache_block(this_fs->fs_dev, *(uint32_t *)inode->data);
+ memcpy(symlink_buf, cs->data, inode->size);
+ }
+ p = symlink_buf + inode->size;
+
+ if (*name_left)
+ *p++ = '/';
+ if (strecpy(p, name_left, symlink_buf + BLOCK_SIZE(this_fs))) {
+ free(symlink_buf);
+ return NULL;
+ }
+ if(!(p = strdup(symlink_buf)))
+ return symlink_buf;
+
+ free(symlink_buf);
+ return p;
+}
+
+/*
+ * Read one directory entry at a time
+ */
+static struct dirent * ext2_readdir(struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct dirent *dirent;
+ struct ext2_dir_entry *de;
+ struct cache_struct *cs;
+ int index = file->offset >> fs->block_shift;
+ block_t block;
+
+ if (!(block = bmap(fs, inode, index)))
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block);
+ de = (struct ext2_dir_entry *)(cs->data + (file->offset & (BLOCK_SIZE(fs) - 1)));
+
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in ext2_readdir");
+ return NULL;
+ }
+ dirent->d_ino = de->d_inode;
+ dirent->d_off = file->offset;
+ dirent->d_reclen = de->d_rec_len;
+ dirent->d_type = de->d_file_type;
+ memcpy(dirent->d_name, de->d_name, de->d_name_len);
+ dirent->d_name[de->d_name_len] = '\0';
+
+ file->offset += de->d_rec_len; /* Update for next reading */
+
+ return dirent;
+}
+
+/* Load the config file, return 1 if failed, or 0 */
+static int ext2_load_config(void)
+{
+ char *config_name = "extlinux.conf";
+ com32sys_t regs;
+
+ strcpy(ConfigName, config_name);
+ *(uint32_t *)CurrentDirName = 0x00002f2e;
+
+ memset(&regs, 0, sizeof regs);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+
+ return !!(regs.eflags.l & EFLAGS_ZF);
+}
+
+
+/*
+ * init. the fs meta data, return the block size bits.
+ */
+static int ext2_fs_init(struct fs_info *fs)
+{
+ struct disk *disk = fs->fs_dev->disk;
+ struct ext2_sb_info *sbi;
+ struct ext2_super_block sb;
+ int blk_bits;
+ int db_count;
+ int i;
+ int desc_block;
+ char *desc_buffer;
+
+ /* read the super block */
+ disk->rdwr_sectors(disk, &sb, 2, 2, 0);
+
+ /* check if it is ext2, since we also support btrfs now */
+ if (sb.s_magic != EXT2_SUPER_MAGIC)
+ return -1;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("ext2_sb_info structure");
+ return -1;
+ }
+ fs->fs_info = sbi;
+
+ if (sb.s_magic != EXT2_SUPER_MAGIC) {
+ printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
+ return 0;
+ }
+
+ fs->sector_shift = disk->sector_shift;
+ fs->block_shift = sb.s_log_block_size + 10;
+
+ sbi->s_inodes_per_group = sb.s_inodes_per_group;
+ sbi->s_blocks_per_group = sb.s_blocks_per_group;
+ sbi->s_inodes_per_block = BLOCK_SIZE(fs) / sb.s_inode_size;
+ if (sb.s_desc_size < sizeof(struct ext2_group_desc))
+ sb.s_desc_size = sizeof(struct ext2_group_desc);
+ sbi->s_desc_per_block = BLOCK_SIZE(fs) / sb.s_desc_size;
+ sbi->s_groups_count = (sb.s_blocks_count - sb.s_first_data_block
+ + EXT2_BLOCKS_PER_GROUP(fs) - 1)
+ / EXT2_BLOCKS_PER_GROUP(fs);
+ db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(fs) - 1) /
+ EXT2_DESC_PER_BLOCK(fs);
+ sbi->s_inode_size = sb.s_inode_size;
+
+ /* read the descpritors */
+ desc_block = sb.s_first_data_block + 1;
+ desc_buffer = malloc(db_count * BLOCK_SIZE(fs));
+ if (!desc_buffer) {
+ malloc_error("desc_buffer");
+ return -1;
+ }
+ blk_bits = fs->block_shift - fs->sector_shift;
+ disk->rdwr_sectors(disk, desc_buffer, desc_block << blk_bits,
+ db_count << blk_bits, 0);
+ sbi->s_group_desc = malloc(sizeof(struct ext2_group_desc *)
+ * sbi->s_groups_count);
+ if (!sbi->s_group_desc) {
+ malloc_error("sbi->s_group_desc");
+ return -1;
+ }
+ for (i = 0; i < (int)sbi->s_groups_count; i++) {
+ sbi->s_group_desc[i] = (struct ext2_group_desc *)desc_buffer;
+ desc_buffer += sb.s_desc_size;
+ }
+
+ return fs->block_shift;
+}
+
+const struct fs_ops ext2_fs_ops = {
+ .fs_name = "ext2",
+ .fs_flags = FS_USEMEM,
+ .fs_init = ext2_fs_init,
+ .searchdir = NULL,
+ .getfssec = ext2_getfssec,
+ .close_file = ext2_close_file,
+ .mangle_name = generic_mangle_name,
+ .unmangle_name = generic_unmangle_name,
+ .load_config = ext2_load_config,
+ .iget_root = ext2_iget_root,
+ .iget_current = ext2_iget_current,
+ .iget = ext2_iget,
+ .follow_symlink = ext2_follow_symlink,
+ .readdir = ext2_readdir
+};
diff --git a/core/fs/ext2/ext2_fs.h b/core/fs/ext2/ext2_fs.h
new file mode 100644
index 00000000..0249ee16
--- /dev/null
+++ b/core/fs/ext2/ext2_fs.h
@@ -0,0 +1,305 @@
+#ifndef __EXT2_FS_H
+#define __EXT2_FS_H
+
+#include <stdint.h>
+
+#define EXT2_SUPER_MAGIC 0xEF53
+
+#define EXT2_GOOD_OLD_REV 0 // The good old (original) format
+#define EXT2_DYNAMIC_REV 1 // V2 format w/ dynamic inode sizes
+#define EXT2_GOOD_OLD_INODE_SIZE 128
+
+// Special inode numbers
+#define EXT2_BAD_INO 1 // Bad blocks inode
+#define EXT2_ROOT_INO 2 // Root inode
+#define EXT2_BOOT_LOADER_INO 5 // Boot loader inode
+#define EXT2_UNDEL_DIR_INO 6 // Undelete directory inode
+#define EXT3_RESIZE_INO 7 // Reserved group descriptors inode
+#define EXT3_JOURNAL_INO 8 // Journal inode
+
+// We're readonly, so we only care about incompat features.
+#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004
+#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008
+#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff
+
+#define EXT2_NDIR_BLOCKS 12
+#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
+#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK+1)
+#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK+1)
+#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK+1)
+
+
+/* for EXT4 extent */
+#define EXT4_EXT_MAGIC 0xf30a
+#define EXT4_EXTENTS_FLAG 0x00080000
+
+/*
+ * File types and file modes
+ */
+#define S_IFDIR 0040000 // Directory
+#define S_IFCHR 0020000 // Character device
+#define S_IFBLK 0060000 // Block device
+#define S_IFREG 0100000 // Regular file
+#define S_IFIFO 0010000 // FIFO
+#define S_IFLNK 0120000 // Symbolic link
+#define S_IFSOCK 0140000 // Socket
+
+#define S_IFSHIFT 12
+
+#define T_IFDIR (S_IFDIR >> S_IFSHIFT)
+#define T_IFCHR (S_IFCHR >> S_IFSHIFT)
+#define T_IFBLK (S_IFBLK >> S_IFSHIFT)
+#define T_IFREG (S_IFREG >> S_IFSHIFT)
+#define T_IFIFO (S_IFIFO >> S_IFSHIFT)
+#define T_IFLNK (S_IFLNK >> S_IFSHIFT)
+#define T_IFSOCK (S_IFSOCK >> S_IFSHIFT)
+
+
+#define ext2_group_desc_lg2size 5
+
+
+
+/*
+ * super block structure:
+ * include/linux/ext2_fs.h
+ */
+struct ext2_super_block {
+ uint32_t s_inodes_count; /* Inodes count */
+ uint32_t s_blocks_count; /* Blocks count */
+ uint32_t s_r_blocks_count; /* Reserved blocks count */
+ uint32_t s_free_blocks_count; /* Free blocks count */
+ uint32_t s_free_inodes_count; /* Free inodes count */
+ uint32_t s_first_data_block; /* First Data Block */
+ uint32_t s_log_block_size; /* Block size */
+ uint32_t s_log_frag_size; /* Fragment size */
+ uint32_t s_blocks_per_group; /* # Blocks per group */
+ uint32_t s_frags_per_group; /* # Fragments per group */
+ uint32_t s_inodes_per_group; /* # Inodes per group */
+ uint32_t s_mtime; /* Mount time */
+ uint32_t s_wtime; /* Write time */
+ uint16_t s_mnt_count; /* Mount count */
+ int16_t s_max_mnt_count; /* Maximal mount count */
+ uint16_t s_magic; /* Magic signature */
+ uint16_t s_state; /* File system state */
+ uint16_t s_errors; /* Behaviour when detecting errors */
+ uint16_t s_minor_rev_level;
+ uint32_t s_lastcheck; /* time of last check */
+ uint32_t s_checkinterval; /* max. time between checks */
+ uint32_t s_creator_os; /* OS */
+ uint32_t s_rev_level; /* Revision level */
+ uint16_t s_def_resuid; /* Default uid for reserved blocks */
+ uint16_t s_def_resgid; /* Default gid for reserved blocks */
+
+ uint32_t s_first_ino; /* First non-reserved inode */
+ uint16_t s_inode_size; /* size of inode structure */
+ uint16_t s_block_group_nr; /* block group # of this superblock */
+ uint32_t s_feature_compat; /* compatible feature set */
+ uint32_t s_feature_incompat; /* incompatible feature set */
+ uint32_t s_feature_ro_compat; /* readonly-compatible feature set */
+ uint8_t s_uuid[16]; /* 128-bit uuid for volume */
+ char s_volume_name[16]; /* volume name */
+ char s_last_mounted[64]; /* directory where last mounted */
+ uint32_t s_algorithm_usage_bitmap; /* For compression */
+ uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ uint8_t s_prealloc_dir_blocks;
+ uint16_t s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */
+ uint32_t s_journal_inum; /* inode number of journal file */
+ uint32_t s_journal_dev; /* device number of journal file */
+ uint32_t s_last_orphan; /* start of list of inodes to delete */
+ uint32_t s_hash_seed[4]; /* HTREE hash seed */
+ uint8_t s_def_hash_version; /* Default hash version to use */
+ uint8_t s_reserved_char_pad;
+ uint16_t s_desc_size; /* size of group descriptor */
+ uint32_t s_default_mount_opts;
+ uint32_t s_first_meta_bg; /* First metablock block group */
+ uint32_t s_mkfs_time; /* When the filesystem was created */
+ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+ uint32_t s_blocks_count_hi; /* Blocks count */
+ uint32_t s_r_blocks_count_hi; /* Reserved blocks count */
+ uint32_t s_free_blocks_count_hi;/* Free blocks count */
+ uint16_t s_min_extra_isize; /* All inodes have at least # bytes */
+ uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */
+ uint32_t s_flags; /* Miscellaneous flags */
+ uint16_t s_raid_stride; /* RAID stride */
+ uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */
+ uint64_t s_mmp_block; /* Block for multi-mount protection */
+ uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ uint8_t s_log_groups_per_flex; /* FLEX_BG group size */
+ uint8_t s_reserved_char_pad2;
+ uint16_t s_reserved_pad;
+ uint32_t s_reserved[162]; /* Padding to the end of the block */
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_super_block_size != 1024
+#error ext2_super_block definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+/*
+ * ext2 group desc structure:
+ */
+struct ext2_group_desc {
+ uint32_t bg_block_bitmap; /* Blocks bitmap block */
+ uint32_t bg_inode_bitmap; /* Inodes bitmap block */
+ uint32_t bg_inode_table; /* Inodes table block */
+ uint16_t bg_free_blocks_count; /* Free blocks count */
+ uint16_t bg_free_inodes_count; /* Free inodes count */
+ uint16_t bg_used_dirs_count; /* Directories count */
+ uint16_t bg_pad;
+ uint32_t bg_reserved[3];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_group_desc_size != 32
+#error ext2_group_desc definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+/*
+ * ext2 inode structure:
+ */
+struct ext2_inode {
+ uint16_t i_mode; /* File mode */
+ uint16_t i_uid; /* Owner Uid */
+ uint32_t i_size; /* 4: Size in bytes */
+ uint32_t i_atime; /* Access time */
+ uint32_t i_ctime; /* 12: Creation time */
+ uint32_t i_mtime; /* Modification time */
+ uint32_t i_dtime; /* 20: Deletion Time */
+ uint16_t i_gid; /* Group Id */
+ uint16_t i_links_count; /* 24: Links count */
+ uint32_t i_blocks; /* Blocks count */
+ uint32_t i_flags; /* 32: File flags */
+ uint32_t l_i_reserved1;
+ uint32_t i_block[EXT2_N_BLOCKS]; /* 40: Pointers to blocks */
+ uint32_t i_version; /* File version (for NFS) */
+ uint32_t i_file_acl; /* File ACL */
+ uint32_t i_dir_acl; /* Directory ACL */
+ uint32_t i_faddr; /* Fragment address */
+ uint8_t l_i_frag; /* Fragment number */
+ uint8_t l_i_fsize; /* Fragment size */
+ uint16_t i_pad1;
+ uint32_t l_i_reserved2[2];
+};
+
+/*******************************************************************************
+#ifndef DEPEND
+#if ext2_inode_size != 128
+#error ext2_inode definition bogus
+#endif
+#endif
+*******************************************************************************/
+
+
+#define EXT2_NAME_LEN 255
+struct ext2_dir_entry {
+ unsigned int d_inode; /* Inode number */
+ unsigned short d_rec_len; /* Directory entry length */
+ unsigned char d_name_len; /* Name length */
+ unsigned char d_file_type;
+ char d_name[EXT2_NAME_LEN]; /* File name */
+};
+
+/*******************************************************************************
+#define EXT2_DIR_PAD 4
+#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
+#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
+ ~EXT2_DIR_ROUND)
+*******************************************************************************/
+
+
+
+
+
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+ uint32_t ee_block; /* first logical block extent covers */
+ uint16_t ee_len; /* number of blocks covered by extent */
+ uint16_t ee_start_hi; /* high 16 bits of physical block */
+ uint32_t ee_start_lo; /* low 32 bits of physical block */
+};
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_idx {
+ uint32_t ei_block; /* index covers logical blocks from 'block' */
+ uint32_t ei_leaf_lo; /* pointer to the physical block of the next *
+ * level. leaf or next index could be there */
+ uint16_t ei_leaf_hi; /* high 16 bits of physical block */
+ uint16_t ei_unused;
+};
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+ uint16_t eh_magic; /* probably will support different formats */
+ uint16_t eh_entries; /* number of valid entries */
+ uint16_t eh_max; /* capacity of store in entries */
+ uint16_t eh_depth; /* has tree real underlying blocks? */
+ uint32_t eh_generation; /* generation of the tree */
+};
+
+
+
+#define EXT4_FIRST_EXTENT(header) ( (struct ext4_extent *)(header + 1) )
+#define EXT4_FIRST_INDEX(header) ( (struct ext4_extent_idx *) (header + 1) )
+
+
+/*
+ * The ext2 super block information in memory
+ */
+struct ext2_sb_info {
+ uint32_t s_inodes_per_block;/* Number of inodes per block */
+ uint32_t s_inodes_per_group;/* Number of inodes in a group */
+ uint32_t s_blocks_per_group;/* Number of blocks in a group */
+ uint32_t s_desc_per_block; /* Number of group descriptors per block */
+ uint32_t s_groups_count; /* Number of groups in the fs */
+ int s_inode_size;
+
+ /*
+ * Here did not like Linux Kernel did; the group descriptor cache
+ * here is based on ext2_group_desc structure, instead of buffer
+ * head structure in Linux Kernel, where cache one block data.
+ */
+ struct ext2_group_desc ** s_group_desc;
+};
+
+static inline struct ext2_sb_info *EXT2_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+#define EXT2_BLOCKS_PER_GROUP(fs) (EXT2_SB(fs)->s_blocks_per_group)
+#define EXT2_INODES_PER_GROUP(fs) (EXT2_SB(fs)->s_inodes_per_group)
+#define EXT2_INODES_PER_BLOCK(fs) (EXT2_SB(fs)->s_inodes_per_block)
+#define EXT2_DESC_PER_BLOCK(fs) (EXT2_SB(fs)->s_desc_per_block)
+
+
+/*
+ * functions
+ */
+block_t bmap(struct fs_info *, struct inode *, int);
+
+
+#endif /* ext2_fs.h */
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
new file mode 100644
index 00000000..d77fcb12
--- /dev/null
+++ b/core/fs/fat/fat.c
@@ -0,0 +1,764 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <cache.h>
+#include <core.h>
+#include <disk.h>
+#include <fs.h>
+#include "fat_fs.h"
+
+
+static struct inode * new_fat_inode(void)
+{
+ struct inode *inode = malloc(sizeof(*inode));
+ if (!inode)
+ malloc_error("inode structure");
+ memset(inode, 0, sizeof(*inode));
+
+ /*
+ * We just need allocate one uint32_t data to store the
+ * first cluster number.
+ */
+ inode->data = malloc(sizeof(uint32_t));
+ if (!inode->data)
+ malloc_error("inode->data");
+
+ return inode;
+}
+
+
+static void vfat_close_file(struct file *file)
+{
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
+}
+
+
+/*
+ * Check for a particular sector in the FAT cache
+ */
+static struct cache_struct * get_fat_sector(struct fs_info *fs, sector_t sector)
+{
+ return get_cache_block(fs->fs_dev, FAT_SB(fs)->fat + sector);
+}
+
+static uint32_t get_next_cluster(struct fs_info *fs, uint32_t clust_num)
+{
+ uint32_t next_cluster;
+ sector_t fat_sector;
+ uint32_t offset;
+ int lo, hi;
+ struct cache_struct *cs;
+
+ switch(FAT_SB(fs)->fat_type) {
+ case FAT12:
+ fat_sector = (clust_num + clust_num / 2) >> SECTOR_SHIFT;
+ cs = get_fat_sector(fs, fat_sector);
+ offset = (clust_num * 3 / 2) & ((1 << SECTOR_SHIFT) - 1);
+ if (offset == 0x1ff) {
+ /*
+ * we got the end of the one fat sector,
+ * but we don't got we have(just one byte, we need two),
+ * so store the low part, then read the next fat
+ * sector, read the high part, then combine it.
+ */
+ lo = *(uint8_t *)(cs->data + offset);
+ cs = get_fat_sector(fs, fat_sector + 1);
+ hi = *(uint8_t *)cs->data;
+ next_cluster = (hi << 8) + lo;
+ } else {
+ next_cluster = *(uint16_t *)(cs->data + offset);
+ }
+
+ if (clust_num & 0x0001)
+ next_cluster >>= 4; /* cluster number is ODD */
+ else
+ next_cluster &= 0x0fff; /* cluster number is EVEN */
+ if (next_cluster > 0x0ff0)
+ goto fail;
+ break;
+
+ case FAT16:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 1);
+ offset = clust_num & ((1 << (SECTOR_SHIFT-1)) -1);
+ cs = get_fat_sector(fs, fat_sector);
+ next_cluster = ((uint16_t *)cs->data)[offset];
+ if (next_cluster > 0xfff0)
+ goto fail;
+ break;
+
+ case FAT32:
+ fat_sector = clust_num >> (SECTOR_SHIFT - 2);
+ offset = clust_num & ((1 << (SECTOR_SHIFT-2)) -1);
+ cs = get_fat_sector(fs, fat_sector);
+ next_cluster = ((uint32_t *)cs->data)[offset] & 0x0fffffff;
+ if (next_cluster > 0x0ffffff0)
+ goto fail;
+ break;
+ }
+
+ return next_cluster;
+
+fail:
+ /* got an unexcepted cluster number, so return ZERO */
+ return 0;
+}
+
+
+static sector_t get_next_sector(struct fs_info* fs, uint32_t sector)
+{
+ sector_t data_area = FAT_SB(fs)->data;
+ sector_t data_sector;
+ uint32_t cluster;
+
+ if (sector < data_area) {
+ sector++;
+ /* if we reached the end of root area */
+ if (sector == data_area)
+ sector = 0; /* return 0 */
+ return sector;
+ }
+
+ data_sector = sector - data_area;
+ if ((data_sector + 1) & FAT_SB(fs)->clust_mask) /* in a cluster */
+ return ++sector;
+
+ /* get a new cluster */
+ cluster = get_next_cluster(fs, (data_sector >> FAT_SB(fs)->clust_shift) + 2);
+ if (!cluster )
+ return 0;
+
+ /* return the start of the new cluster */
+ sector = ((cluster - 2) << FAT_SB(fs)->clust_shift) + data_area;
+ return sector;
+}
+
+/*
+ * Here comes the place I don't like VFAT fs most; if we need seek
+ * the file to the right place, we need get the right sector address
+ * from begining everytime! Since it's a kind a signle link list, we
+ * need to traver from the head-node to find the right node in that list.
+ *
+ * What a waste of time!
+ */
+static sector_t get_the_right_sector(struct file *file)
+{
+ int i = 0;
+ int sector_pos = file->offset >> SECTOR_SHIFT;
+ sector_t sector = *file->inode->data;
+
+ for (; i < sector_pos; i++)
+ sector = get_next_sector(file->fs, sector);
+
+ return sector;
+}
+
+/**
+ * __getfssec:
+ *
+ * get multiple sectors from a file
+ *
+ * This routine makes sure the subransfers do not cross a 64K boundary
+ * and will correct the situation if it does, UNLESS *sectos* cross
+ * 64K boundaries.
+ *
+ */
+static void __getfssec(struct fs_info *fs, char *buf,
+ struct file *file, uint32_t sectors)
+{
+ sector_t curr_sector = get_the_right_sector(file);
+ sector_t frag_start , next_sector;
+ uint32_t con_sec_cnt;
+ struct disk *disk = fs->fs_dev->disk;
+
+ while (sectors) {
+ /* get fragment */
+ con_sec_cnt = 0;
+ frag_start = curr_sector;
+
+ do {
+ /* get consective sector count */
+ con_sec_cnt ++;
+ sectors --;
+ if (sectors == 0)
+ break;
+
+ next_sector = get_next_sector(fs, curr_sector);
+ if (!next_sector)
+ break;
+ }while(next_sector == (++curr_sector));
+
+#if 0
+ printf("You are reading data stored at sector --0x%x--0x%x\n",
+ frag_start, frag_start + con_sec_cnt -1);
+#endif
+
+ /* do read */
+ disk->rdwr_sectors(disk, buf, frag_start, con_sec_cnt, 0);
+ buf += con_sec_cnt << SECTOR_SHIFT;/* adjust buffer pointer */
+
+ if (!sectors)
+ break;
+
+ curr_sector = next_sector;
+ }
+
+}
+
+
+
+/**
+ * get multiple sectors from a file
+ *
+ * @param: buf, the buffer to store the read data
+ * @param: file, the file structure pointer
+ * @param: sectors, number of sectors wanna read
+ * @param: have_more, set one if has more
+ *
+ * @return: number of bytes read
+ *
+ */
+static uint32_t vfat_getfssec(struct file *file, char *buf, int sectors,
+ bool *have_more)
+{
+ struct fs_info *fs = file->fs;
+ uint32_t bytes_left = file->inode->size - file->offset;
+ uint32_t bytes_read = sectors << fs->sector_shift;
+ int sector_left;
+
+ sector_left = (bytes_left + SECTOR_SIZE(fs) - 1) >> fs->sector_shift;
+ if (sectors > sector_left)
+ sectors = sector_left;
+
+ __getfssec(fs, buf, file, sectors);
+
+ if (bytes_read >= bytes_left) {
+ bytes_read = bytes_left;
+ *have_more = 0;
+ } else {
+ *have_more = 1;
+ }
+ file->offset += bytes_read;
+
+ return bytes_read;
+}
+
+/*
+ * Mangle a filename pointed to by src into a buffer pointed to by dst;
+ * ends on encountering any whitespace.
+ *
+ */
+static void vfat_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ char c;
+ int i = FILENAME_MAX -1;
+
+ /*
+ * Copy the filename, converting backslash to slash and
+ * collapsing duplicate separators.
+ */
+ while (not_whitespace(c = *src)) {
+ if (c == '\\')
+ c = '/';
+
+ if (c == '/') {
+ if (src[1] == '/' || src[1] == '\\') {
+ src++;
+ i--;
+ continue;
+ }
+ }
+ i--;
+ *dst++ = *src++;
+ }
+
+ /* Strip terminal slashes or whitespace */
+ while (1) {
+ if (dst == p)
+ break;
+ if (*(dst-1) == '/' && dst-1 == p) /* it's the '/' case */
+ break;
+ if ((*(dst-1) != '/') && (*(dst-1) != '.'))
+ break;
+
+ dst--;
+ i++;
+ }
+
+ i++;
+ for (; i > 0; i --)
+ *dst++ = '\0';
+}
+
+/*
+ * Mangle a normal style string to DOS style string.
+ */
+static void mangle_dos_name(char *mangle_buf, char *src)
+{
+ char *dst = mangle_buf;
+ int i = 0;
+ unsigned char c;
+
+ for (; i < 11; i ++)
+ mangle_buf[i] = ' ';
+
+ for (i = 0; i < 11; i++) {
+ c = *src ++;
+
+ if ((c <= ' ') || (c == '/'))
+ break;
+
+ if (c == '.') {
+ dst = &mangle_buf[8];
+ i = 7;
+ continue;
+ }
+
+ if (c >= 'a' && c <= 'z')
+ c -= 32;
+ if ((c == 0xe5) && (i == 11))
+ c = 0x05;
+
+ *dst++ = c;
+ }
+ mangle_buf[11] = '\0';
+}
+
+
+/* try with the biggest long name */
+static char long_name[0x40 * 13];
+static char entry_name[14];
+
+static void unicode_to_ascii(char *entry_name, uint16_t *unicode_buf)
+{
+ int i = 0;
+
+ for (; i < 13; i++) {
+ if (unicode_buf[i] == 0xffff) {
+ entry_name[i] = '\0';
+ return;
+ }
+ entry_name[i] = (char)unicode_buf[i];
+ }
+}
+
+/*
+ * get the long entry name
+ *
+ */
+static void long_entry_name(struct fat_long_name_entry *dir)
+{
+ uint16_t unicode_buf[13];
+
+ memcpy(unicode_buf, dir->name1, 5 * 2);
+ memcpy(unicode_buf + 5, dir->name2, 6 * 2);
+ memcpy(unicode_buf + 11, dir->name3, 2 * 2);
+
+ unicode_to_ascii(entry_name, unicode_buf);
+}
+
+
+static uint8_t get_checksum(char *dir_name)
+{
+ int i;
+ uint8_t sum = 0;
+
+ for (i = 11; i; i--)
+ sum = ((sum & 1) << 7) + (sum >> 1) + *dir_name++;
+ return sum;
+}
+
+
+/* compute the first sector number of one dir where the data stores */
+static inline sector_t first_sector(struct fat_dir_entry *dir)
+{
+ struct fat_sb_info *sbi = FAT_SB(this_fs);
+ uint32_t first_clust;
+ sector_t sector;
+
+ first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low;
+ sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data;
+
+ return sector;
+}
+
+static inline int get_inode_mode(uint8_t attr)
+{
+ if (attr == FAT_ATTR_DIRECTORY)
+ return I_DIR;
+ else
+ return I_FILE;
+}
+
+
+static struct inode *vfat_find_entry(char *dname, struct inode *dir)
+{
+ struct inode *inode = new_fat_inode();
+ struct fat_dir_entry *de;
+ struct fat_long_name_entry *long_de;
+ struct cache_struct *cs;
+
+ char mangled_name[12] = {0, };
+ sector_t dir_sector = *dir->data;
+
+ uint8_t vfat_init, vfat_next, vfat_csum = 0;
+ uint8_t id;
+ int slots;
+ int entries;
+ int checksum;
+ int long_match = 0;
+
+ slots = (strlen(dname) + 12) / 13 ;
+ slots |= 0x40;
+ vfat_init = vfat_next = slots;
+
+ while (1) {
+ cs = get_cache_block(this_fs->fs_dev, dir_sector);
+ de = (struct fat_dir_entry *)cs->data;
+ entries = 1 << (this_fs->sector_shift - 5);
+
+ while(entries--) {
+ if (de->name[0] == 0)
+ return NULL;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
+ if (id != vfat_next)
+ goto not_match;
+
+ if (id & 0x40) {
+ /* get the initial checksum value */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum)
+ goto not_match;
+ }
+
+ vfat_next = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_de);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ /*
+ * If we got the last entry, check it.
+ * Or, go on with the next entry.
+ */
+ if (id == 0) {
+ if (strcmp(long_name, dname))
+ goto not_match;
+ long_match = 1;
+ }
+
+ de++;
+ continue; /* Try the next entry */
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto not_match;
+
+ if (long_match == 1) {
+ /*
+ * We already have a VFAT long name match. However, the
+ * match is only valid if the checksum matches.
+ *
+ * Well, let's trun the long_match flag off first.
+ */
+ long_match = 0;
+ checksum = get_checksum(de->name);
+ if (checksum == vfat_csum)
+ goto found; /* Got it */
+ } else {
+ if (mangled_name[0] == 0) {
+ /* We haven't mangled it, mangle it first. */
+ mangle_dos_name(mangled_name, dname);
+ }
+
+ if (!strncmp(mangled_name, de->name, 11))
+ goto found;
+ }
+ }
+
+ not_match:
+ vfat_next = vfat_init;
+
+ de++;
+ }
+
+ /* Try with the next sector */
+ dir_sector = get_next_sector(this_fs, dir_sector);
+ if (!dir_sector)
+ return NULL;
+ }
+
+found:
+ inode->size = de->file_size;
+ *inode->data = first_sector(de);
+ inode->mode = get_inode_mode(de->attr);
+
+ return inode;
+}
+
+static struct inode *vfat_iget_root(void)
+{
+ struct inode *inode = new_fat_inode();
+ int root_size = FAT_SB(this_fs)->root_size;
+
+ inode->size = root_size << this_fs->sector_shift;
+ *inode->data = FAT_SB(this_fs)->root;
+ inode->mode = I_DIR;
+
+ return inode;
+}
+
+static struct inode *vfat_iget(char *dname, struct inode *parent)
+{
+ return vfat_find_entry(dname, parent);
+}
+
+static struct dirent * vfat_readdir(struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct dirent *dirent;
+ struct fat_dir_entry *de;
+ struct fat_long_name_entry *long_de;
+ struct cache_struct *cs;
+
+ sector_t sector = get_the_right_sector(file);
+
+ uint8_t vfat_init, vfat_next, vfat_csum;
+ uint8_t id;
+ int entries_left;
+ int checksum;
+ int long_entry = 0;
+ int sec_off = file->offset & ((1 << fs->sector_shift) - 1);
+
+ cs = get_cache_block(fs->fs_dev, sector);
+ de = (struct fat_dir_entry *)(cs->data + sec_off);
+ entries_left = ((1 << fs->sector_shift) - sec_off) >> 5;
+
+ while (1) {
+ while(entries_left--) {
+ if (de->name[0] == 0)
+ return NULL;
+ if ((uint8_t)de->name[0] == 0xe5)
+ goto invalid;
+
+ if (de->attr == 0x0f) {
+ /*
+ * It's a long name entry.
+ */
+ long_de = (struct fat_long_name_entry *)de;
+ id = long_de->id;
+
+ if (id & 0x40) {
+ /* init vfat_csum and vfat_init */
+ vfat_csum = long_de->checksum;
+ id &= 0x3f;
+ vfat_init = id;
+
+ /* ZERO the long_name buffer */
+ memset(long_name, 0, sizeof long_name);
+ } else {
+ if (long_de->checksum != vfat_csum ||
+ id != vfat_next)
+ goto invalid;
+ }
+
+ vfat_next = --id;
+
+ /* got the long entry name */
+ long_entry_name(long_de);
+ memcpy(long_name + id * 13, entry_name, 13);
+
+ if (id == 0)
+ long_entry = 1;
+
+ de++;
+ file->offset += sizeof(struct fat_dir_entry);
+ continue; /* Try the next entry */
+ } else {
+ /*
+ * It's a short entry
+ */
+ if (de->attr & 0x08) /* ignore volume labels */
+ goto invalid;
+
+ if (long_entry == 1) {
+ /* Got a long entry */
+ checksum = get_checksum(de->name);
+ if (checksum == vfat_csum)
+ goto got;
+ } else {
+ /* Use the long_name buffer to store a short one. */
+ int i;
+ char *p = long_name;
+
+ for (i = 0; i < 8; i++) {
+ if (de->name[i] == ' ')
+ break;
+ *p++ = de->name[i];
+ }
+ *p++ = '.';
+ if (de->name[8] == ' ') {
+ *--p = '\0';
+ } else {
+ for (i = 8; i < 11; i++) {
+ if (de->name[i] == ' ')
+ break;
+ *p++ = de->name[i];
+ }
+ *p = '\0';
+ }
+
+ goto got;
+ }
+ }
+
+ invalid:
+ de++;
+ file->offset += sizeof(struct fat_dir_entry);
+ }
+
+ /* Try with the next sector */
+ sector = get_next_sector(fs, sector);
+ if (!sector)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, sector);
+ de = (struct fat_dir_entry *)cs->data;
+ entries_left = 1 << (fs->sector_shift - 5);
+ }
+
+got:
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in vfat_readdir");
+ return NULL;
+ }
+ dirent->d_ino = 0; /* Inode number is invalid to FAT fs */
+ dirent->d_off = file->offset;
+ dirent->d_reclen = 0;
+ dirent->d_type = get_inode_mode(de->attr);
+ strcpy(dirent->d_name, long_name);
+
+ file->offset += sizeof(*de); /* Update for next reading */
+
+ return dirent;
+}
+
+/* Load the config file, return 1 if failed, or 0 */
+static int vfat_load_config(void)
+{
+ const char * const syslinux_cfg[] = {
+ "/boot/syslinux/syslinux.cfg",
+ "/syslinux/syslinux.cfg",
+ "/syslinux.cfg"
+ };
+ com32sys_t regs;
+ char *p;
+ int i = 0;
+
+ /*
+ * we use the ConfigName to pass the config path because
+ * it is under the address 0xffff
+ */
+ memset(&regs, 0, sizeof regs);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ for (; i < 3; i++) {
+ strcpy(ConfigName, syslinux_cfg[i]);
+ call16(core_open, &regs, &regs);
+
+ /* if zf flag set, then failed; try another */
+ if (! (regs.eflags.l & EFLAGS_ZF))
+ break;
+ }
+ if (i == 3) {
+ printf("no config file found\n");
+ return 1; /* no config file */
+ }
+
+ strcpy(ConfigName, "syslinux.cfg");
+ strcpy(CurrentDirName, syslinux_cfg[i]);
+ p = strrchr(CurrentDirName, '/');
+ *(p + 1) = '\0'; /* In case we met '/syslinux.cfg' */
+
+ return 0;
+}
+
+static inline __constfunc uint32_t bsr(uint32_t num)
+{
+ asm("bsrl %1,%0" : "=r" (num) : "rm" (num));
+ return num;
+}
+
+/* init. the fs meta data, return the block size in bits */
+static int vfat_fs_init(struct fs_info *fs)
+{
+ struct fat_bpb fat;
+ struct fat_sb_info *sbi;
+ struct disk *disk = fs->fs_dev->disk;
+ int sectors_per_fat;
+ uint32_t clust_num;
+ sector_t total_sectors;
+
+ fs->sector_shift = fs->block_shift = disk->sector_shift;
+ disk->rdwr_sectors(disk, &fat, 0, 1, 0);
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi)
+ malloc_error("fat_sb_info structure");
+ fs->fs_info = sbi;
+ this_fs = fs;
+
+ sectors_per_fat = fat.bxFATsecs ? : fat.u.fat32.bxFATsecs_32;
+ total_sectors = fat.bxSectors ? : fat.bsHugeSectors;
+
+ sbi->fat = fat.bxResSectors;
+ sbi->root = sbi->fat + sectors_per_fat * fat.bxFATs;
+ sbi->root_size = root_dir_size(&fat);
+ sbi->data = sbi->root + sbi->root_size;
+
+ sbi->clust_shift = bsr(fat.bxSecPerClust);
+ sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift;
+ sbi->clust_mask = fat.bxSecPerClust - 1;
+ sbi->clust_size = fat.bxSecPerClust << fs->sector_shift;
+
+ clust_num = (total_sectors - sbi->data) >> sbi->clust_shift;
+ if (clust_num < 4085)
+ sbi->fat_type = FAT12;
+ else if (clust_num < 65525)
+ sbi->fat_type = FAT16;
+ else
+ sbi->fat_type = FAT32;
+
+ /* for SYSLINUX, the cache is based on sector size */
+ return fs->sector_shift;
+}
+
+const struct fs_ops vfat_fs_ops = {
+ .fs_name = "vfat",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = vfat_fs_init,
+ .searchdir = NULL,
+ .getfssec = vfat_getfssec,
+ .close_file = vfat_close_file,
+ .mangle_name = vfat_mangle_name,
+ .unmangle_name = generic_unmangle_name,
+ .load_config = vfat_load_config,
+ .readdir = vfat_readdir,
+ .iget_root = vfat_iget_root,
+ .iget_current = NULL,
+ .iget = vfat_iget,
+};
diff --git a/core/fs/fat/fat_fs.h b/core/fs/fat/fat_fs.h
new file mode 100644
index 00000000..9453a67f
--- /dev/null
+++ b/core/fs/fat/fat_fs.h
@@ -0,0 +1,145 @@
+#ifndef FAT_FS_H
+#define FAT_FS_H
+
+#include <stdint.h>
+
+#define FAT_DIR_ENTRY_SIZE 32
+#define DIRENT_SHIFT 5
+
+#define FAT_ATTR_READ_ONLY 0x01
+#define FAT_ATTR_HIDDEN 0x02
+#define FAT_ATTR_SYSTEM 0x04
+#define FAT_ATTR_VOLUME_ID 0x08
+#define FAT_ATTR_DIRECTORY 0x10
+#define FAT_ATTR_ARCHIVE 0x20
+
+#define FAT_MAXFILE 256
+
+#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_VOLUME_ID)
+
+#define FAT_ATTR_VALID (FAT_ATTR_READ_ONLY \
+ | FAT_ATTR_HIDDEN \
+ | FAT_ATTR_SYSTEM \
+ | FAT_ATTR_DIRECTORY \
+ | FAT_ATTR_ARCHIVE)
+
+enum fat_type{ FAT12, FAT16, FAT32 };
+
+/*
+ * The fat file system structures
+ */
+
+struct fat_bpb {
+ uint8_t jmp_boot[3];
+ uint8_t oem_name[8];
+ uint16_t sector_size;
+ uint8_t bxSecPerClust;
+ uint16_t bxResSectors;
+ uint8_t bxFATs;
+ uint16_t bxRootDirEnts;
+ uint16_t bxSectors;
+ uint8_t media;
+ uint16_t bxFATsecs;
+ uint16_t sectors_per_track;
+ uint16_t num_heads;
+ uint32_t num_hidden_sectors;
+ uint32_t bsHugeSectors;
+
+ union {
+ struct {
+ uint8_t num_ph_drive;
+ uint8_t reserved;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat12_16;
+
+ struct {
+ uint32_t bxFATsecs_32;
+ uint16_t extended_flags;
+ uint16_t fs_version;
+ uint32_t root_cluster;
+ uint16_t fs_info;
+ uint16_t backup_boot_sector;
+ uint8_t reserved[12];
+ uint8_t num_ph_drive;
+ uint8_t reserved1;
+ uint8_t boot_sig;
+ uint32_t num_serial;
+ uint8_t label[11];
+ uint8_t fstype[8];
+ } __attribute__ ((packed)) fat32;
+
+ } __attribute__ ((packed)) u;
+
+ uint8_t pad[422]; /* padding to 512 Bytes (one sector) */
+
+} __attribute__ ((packed));
+
+/*
+ * The fat file system info in memory
+ */
+struct fat_sb_info {
+ sector_t fat; /* The FAT region */
+ sector_t root; /* The root dir region */
+ int root_size; /* The root dir size in sectores */
+ sector_t data; /* The data region */
+
+ int clust_shift; /* based on sectors */
+ int clust_byte_shift; /* based on bytes */
+ int clust_mask;
+ int clust_size;
+
+ int fat_type;
+} __attribute__ ((packed));
+
+struct fat_dir_entry {
+ char name[11];
+ uint8_t attr;
+ uint8_t nt_reserved;
+ uint8_t c_time_tenth;
+ uint16_t c_time;
+ uint16_t c_date;
+ uint16_t a_date;
+ uint16_t first_cluster_high;
+ uint16_t w_time;
+ uint16_t w_date;
+ uint16_t first_cluster_low;
+ uint32_t file_size;
+} __attribute__ ((packed));
+
+
+
+struct fat_long_name_entry {
+ uint8_t id;
+ uint16_t name1[5];
+ uint8_t attr;
+ uint8_t reserved;
+ uint8_t checksum;
+ uint16_t name2[6];
+ uint16_t first_cluster;
+ uint16_t name3[2];
+} __attribute__ ((packed));
+
+static inline struct fat_sb_info *FAT_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+/*
+ * Count the root dir size in sectors
+ */
+static inline int root_dir_size(struct fat_bpb *fat)
+{
+ int sector_size = 1 << SECTOR_SHIFT;
+
+ return (fat->bxRootDirEnts + sector_size / sizeof(struct fat_dir_entry)
+ - 1) >> (SECTOR_SHIFT - 5);
+}
+
+
+#endif /* fat_fs.h */
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
new file mode 100644
index 00000000..1670e607
--- /dev/null
+++ b/core/fs/iso9660/iso9660.c
@@ -0,0 +1,461 @@
+#include <stdio.h>
+#include <string.h>
+#include <sys/dirent.h>
+#include <core.h>
+#include <cache.h>
+#include <disk.h>
+#include <fs.h>
+#include "iso9660_fs.h"
+
+static struct inode *new_iso_inode(void)
+{
+ struct inode *inode = malloc(sizeof(*inode));
+
+ if (!inode) {
+ malloc_error("inode structure in new_iso_inode");
+ return NULL;
+ }
+ memset(inode, 0, sizeof(*inode));
+
+ inode->data = malloc(sizeof(uint32_t));
+ if (!inode) {
+ malloc_error("inode->data in new_iso_inode");
+ free(inode);
+ return NULL;
+ }
+
+ return inode;
+}
+
+
+static void iso_close_file(struct file *file)
+{
+ if (file->inode) {
+ file->offset = 0;
+ free_inode(file->inode);
+ }
+}
+
+static inline struct iso_sb_info * ISO_SB(struct fs_info *fs)
+{
+ return fs->fs_info;
+}
+
+/*
+ * Mangle a filename pointed to by src into a buffer pointed
+ * to by dst; ends on encountering any whitespace.
+ * dst is preserved.
+ *
+ * This verifies that a filename is < FilENAME_MAX characters,
+ * doesn't contain whitespace, zero-pads the output buffer,
+ * and removes trailing dots and redumndant slashes, so "repe
+ * cmpsb" can do a compare, and the path-searching routine gets
+ * a bit of an easier job.
+ *
+ */
+static void iso_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX - 1;
+
+ while (not_whitespace(*src)) {
+ if ( *src == '/' ) {
+ if ( *(src+1) == '/' ) {
+ i--;
+ src++;
+ continue;
+ }
+ }
+
+ *dst++ = *src ++;
+ i--;
+ }
+
+ while ( 1 ) {
+ if ( dst == p )
+ break;
+
+ if ( (*(dst-1) != '.') && (*(dst-1) != '/') )
+ break;
+
+ dst --;
+ i ++;
+ }
+
+ i ++;
+ for (; i > 0; i -- )
+ *dst++ = '\0';
+}
+
+static int iso_convert_name(char *dst, char *src, int len)
+{
+ int i = 0;
+ char c;
+
+ for (; i < len; i++) {
+ c = src[i];
+ if (!c)
+ break;
+
+ /* remove ';1' in the end */
+ if (c == ';' && i == len - 2 && src[i + 1] == '1')
+ break;
+ /* convert others ';' to '.' */
+ if (c == ';')
+ c = '.';
+ *dst++ = c;
+ }
+
+ /* Then remove the terminal dots */
+ while (*(dst - 1) == '.') {
+ if (i <= 2)
+ break;
+ dst--;
+ i--;
+ }
+ *dst = 0;
+
+ return i;
+}
+
+/*
+ * Unlike strcmp, it does return 1 on match, or reutrn 0 if not match.
+ */
+static int iso_compare_name(char *de_name, int len, char *file_name)
+{
+ char iso_file_name[256];
+ char *p = iso_file_name;
+ char c1, c2;
+ int i;
+
+ i = iso_convert_name(iso_file_name, de_name, len);
+
+ if (i != (int)strlen(file_name))
+ return 0;
+
+ while (i--) {
+ c1 = *p++;
+ c2 = *file_name++;
+
+ /* convert to lower case */
+ c1 |= 0x20;
+ c2 |= 0x20;
+ if (c1 != c2)
+ return 0;
+ }
+
+ return 1;
+}
+
+static inline int cdrom_read_blocks(struct disk *disk, void *buf,
+ int block, int blocks)
+{
+ return disk->rdwr_sectors(disk, buf, block, blocks, 0);
+}
+
+/*
+ * Get multiple clusters from a file, given the file pointer.
+ */
+static uint32_t iso_getfssec(struct file *file, char *buf,
+ int blocks, bool *have_more)
+{
+ struct fs_info *fs = file->fs;
+ struct disk *disk = fs->fs_dev->disk;
+ uint32_t bytes_read = blocks << fs->block_shift;
+ uint32_t bytes_left = file->inode->size - file->offset;
+ uint32_t blocks_left = (bytes_left + BLOCK_SIZE(file->fs) - 1)
+ >> file->fs->block_shift;
+ block_t block = *file->inode->data + (file->offset >> fs->block_shift);
+
+ if (blocks > blocks_left)
+ blocks = blocks_left;
+ cdrom_read_blocks(disk, buf, block, blocks);
+
+ if (bytes_read >= bytes_left) {
+ bytes_read = bytes_left;
+ *have_more = 0;
+ } else {
+ *have_more = 1;
+ }
+
+ file->offset += bytes_read;
+ return bytes_read;
+}
+
+/*
+ * Find a entry in the specified dir with name _dname_.
+ */
+static struct iso_dir_entry *iso_find_entry(char *dname, struct inode *inode)
+{
+ block_t dir_block = *inode->data;
+ int i = 0, offset = 0;
+ char *de_name;
+ int de_name_len, de_len;
+ struct iso_dir_entry *de;
+ struct iso_dir_entry tmpde;
+ struct cache_struct *cs = NULL;
+
+ while (1) {
+ if (!cs) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(this_fs->fs_dev, dir_block++);
+ de = (struct iso_dir_entry *)cs->data;
+ offset = 0;
+ }
+ de = (struct iso_dir_entry *)(cs->data + offset);
+
+ de_len = de->length;
+ if (de_len == 0) { /* move on to the next block */
+ cs = NULL;
+ continue;
+ }
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= BLOCK_SIZE(this_fs)) {
+ int slop = de_len + BLOCK_SIZE(this_fs) - offset;
+
+ memcpy(&tmpde, de, slop);
+ offset &= BLOCK_SIZE(this_fs) - 1;
+ if (offset) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(this_fs->fs_dev, dir_block++);
+ memcpy((void *)&tmpde + slop, cs->data, offset);
+ }
+ de = &tmpde;
+ }
+
+ if (de_len < 33) {
+ printf("Corrupted directory entry in sector %u\n",
+ (uint32_t)(dir_block - 1));
+ return NULL;
+ }
+
+ de_name_len = de->name_len;
+ de_name = de->name;
+ /* Handling the special case ".' and '..' here */
+ if((de_name_len == 1) && (*de_name == 0)) {
+ de_name = ".";
+ } else if ((de_name_len == 1) && (*de_name == 1)) {
+ de_name ="..";
+ de_name_len = 2;
+ }
+ if (iso_compare_name(de_name, de_name_len, dname))
+ return de;
+ }
+}
+
+static inline int get_inode_mode(uint8_t flags)
+{
+ if (flags & 0x02)
+ return I_DIR;
+ else
+ return I_FILE;
+}
+
+static struct inode *iso_get_inode(struct iso_dir_entry *de)
+{
+ struct inode *inode = new_iso_inode();
+
+ if (!inode)
+ return NULL;
+ inode->mode = get_inode_mode(de->flags);
+ inode->size = *(uint32_t *)de->size;
+ *inode->data = *(uint32_t *)de->extent;
+ inode->blocks = (inode->size + BLOCK_SIZE(this_fs) - 1)
+ >> this_fs->block_shift;
+
+ return inode;
+}
+
+
+static struct inode *iso_iget_root(void)
+{
+ struct inode *inode = new_iso_inode();
+ struct iso_dir_entry *root = &ISO_SB(this_fs)->root;
+
+ if (!inode)
+ return NULL;
+
+ inode->mode = I_DIR;
+ inode->size = *(uint32_t *)root->size;
+ *inode->data = *(uint32_t *)root->extent;
+ inode->blocks = (inode->size + BLOCK_SIZE(this_fs) - 1)
+ >> this_fs->block_shift;
+
+ return inode;
+}
+
+static struct inode *iso_iget(char *dname, struct inode *parent)
+{
+ struct iso_dir_entry *de;
+
+ de = iso_find_entry(dname, parent);
+ if (!de)
+ return NULL;
+
+ return iso_get_inode(de);
+}
+
+/* Convert to lower case string */
+static void tolower_str(char *str)
+{
+ while (*str) {
+ if (*str >= 'A' && *str <= 'Z')
+ *str = *str + 0x20;
+ str++;
+ }
+}
+
+static struct dirent *iso_readdir(struct file *file)
+{
+ struct fs_info *fs = file->fs;
+ struct inode *inode = file->inode;
+ struct iso_dir_entry *de, tmpde;
+ struct dirent *dirent;
+ struct cache_struct *cs = NULL;
+ block_t block = *file->inode->data + (file->offset >> fs->block_shift);
+ int offset = file->offset & (BLOCK_SIZE(fs) - 1);
+ int i = 0;
+ int de_len, de_name_len;
+ char *de_name;
+
+ while (1) {
+ if (!cs) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block++);
+ }
+ de = (struct iso_dir_entry *)(cs->data + offset);
+
+ de_len = de->length;
+ if (de_len == 0) { /* move on to the next block */
+ cs = NULL;
+ file->offset = (file->offset + BLOCK_SIZE(fs) - 1)
+ >> fs->block_shift;
+ continue;
+ }
+ offset += de_len;
+
+ /* Make sure we have a full directory entry */
+ if (offset >= BLOCK_SIZE(fs)) {
+ int slop = de_len + BLOCK_SIZE(fs) - offset;
+
+ memcpy(&tmpde, de, slop);
+ offset &= BLOCK_SIZE(fs) - 1;
+ if (offset) {
+ if (++i > inode->blocks)
+ return NULL;
+ cs = get_cache_block(fs->fs_dev, block++);
+ memcpy((void *)&tmpde + slop, cs->data, offset);
+ }
+ de = &tmpde;
+ }
+
+ if (de_len < 33) {
+ printf("Corrupted directory entry in sector %u\n",
+ (uint32_t)(block - 1));
+ return NULL;
+ }
+
+ de_name_len = de->name_len;
+ de_name = de->name;
+ /* Handling the special case ".' and '..' here */
+ if((de_name_len == 1) && (*de_name == 0)) {
+ de_name = ".";
+ } else if ((de_name_len == 1) && (*de_name == 1)) {
+ de_name ="..";
+ de_name_len = 2;
+ }
+
+ break;
+ }
+
+ if (!(dirent = malloc(sizeof(*dirent)))) {
+ malloc_error("dirent structure in iso_readdir");
+ return NULL;
+ }
+
+ dirent->d_ino = 0; /* Inode number is invalid to ISO fs */
+ dirent->d_off = file->offset;
+ dirent->d_reclen = de_len;
+ dirent->d_type = get_inode_mode(de->flags);
+ iso_convert_name(dirent->d_name, de_name, de_name_len);
+ tolower_str(dirent->d_name);
+
+ file->offset += de_len; /* Update for next reading */
+
+ return dirent;
+}
+
+/* Load the config file, return 1 if failed, or 0 */
+static int iso_load_config(void)
+{
+ const char *config_file[] = {
+ "/boot/isolinux/isolinux.cfg",
+ "/isolinux/isolinux.cfg"
+ };
+ com32sys_t regs;
+ int i = 0;
+ char *p;
+
+ for (; i < 2; i++) {
+ memset(&regs, 0, sizeof regs);
+ strcpy(ConfigName, config_file[i]);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_ZF))
+ break;
+ }
+ if (i == 2) {
+ printf("No config file found\n");
+ return 1;
+ }
+
+ strcpy(ConfigName, "isolinux.cfg");
+ strcpy(CurrentDirName, config_file[i]);
+ p = strrchr(CurrentDirName, '/');
+ *p = '\0';
+
+ return 0;
+}
+
+
+static int iso_fs_init(struct fs_info *fs)
+{
+ struct iso_sb_info *sbi;
+
+ this_fs = fs;
+
+ sbi = malloc(sizeof(*sbi));
+ if (!sbi) {
+ malloc_error("iso_sb_info structure");
+ return 1;
+ }
+ fs->fs_info = sbi;
+
+ cdrom_read_blocks(fs->fs_dev->disk, trackbuf, 16, 1);
+ memcpy(&sbi->root, trackbuf + ROOT_DIR_OFFSET, sizeof(sbi->root));
+
+ fs->block_shift = 11;
+ return fs->block_shift;
+}
+
+
+const struct fs_ops iso_fs_ops = {
+ .fs_name = "iso",
+ .fs_flags = FS_USEMEM | FS_THISIND,
+ .fs_init = iso_fs_init,
+ .searchdir = NULL,
+ .getfssec = iso_getfssec,
+ .close_file = iso_close_file,
+ .mangle_name = iso_mangle_name,
+ .unmangle_name = generic_unmangle_name,
+ .load_config = iso_load_config,
+ .iget_root = iso_iget_root,
+ .iget_current = NULL,
+ .iget = iso_iget,
+ .readdir = iso_readdir
+};
diff --git a/core/fs/iso9660/iso9660_fs.h b/core/fs/iso9660/iso9660_fs.h
new file mode 100644
index 00000000..e77ae109
--- /dev/null
+++ b/core/fs/iso9660/iso9660_fs.h
@@ -0,0 +1,27 @@
+#ifndef ISO9660_FS_H
+#define ISO9660_FS_H
+
+#include <stdint.h>
+
+/* The root dir entry offset in the primary volume descriptor */
+#define ROOT_DIR_OFFSET 156
+
+struct iso_dir_entry {
+ uint8_t length; /* 00 */
+ uint8_t ext_attr_length; /* 01 */
+ uint8_t extent[8]; /* 02 */
+ uint8_t size[8]; /* 0a */
+ uint8_t date[7]; /* 12 */
+ uint8_t flags; /* 19 */
+ uint8_t file_unit_size; /* 1a */
+ uint8_t interleave; /* 1b */
+ uint8_t volume_sequence_number[4]; /* 1c */
+ uint8_t name_len; /* 20 */
+ char name[0]; /* 21 */
+};
+
+struct iso_sb_info {
+ struct iso_dir_entry root;
+};
+
+#endif /* iso9660_fs.h */
diff --git a/core/fs/lib/mangle.c b/core/fs/lib/mangle.c
new file mode 100644
index 00000000..813099fb
--- /dev/null
+++ b/core/fs/lib/mangle.c
@@ -0,0 +1,47 @@
+/**
+ * mangle_name:
+ *
+ * Mangle a filename pointed to by src into a buffer pointed
+ * to by dst; ends on encountering any whitespace.
+ * dst is preserved.
+ *
+ * This verifies that a filename is < FILENAME_MAX characters,
+ * doesn't contain whitespace, zero-pads the output buffer,
+ * and removes redundant slashes.
+ *
+ */
+
+#include <string.h>
+#include "fs.h"
+
+void generic_mangle_name(char *dst, const char *src)
+{
+ char *p = dst;
+ int i = FILENAME_MAX-1;
+
+ while (not_whitespace(*src)) {
+ if (*src == '/') {
+ if (src[1] == '/') {
+ src++;
+ i--;
+ continue;
+ }
+ }
+ i--;
+ *dst++ = *src++;
+ }
+
+ while (1) {
+ if (dst == p)
+ break;
+ if (dst[-1] != '/')
+ break;
+
+ dst--;
+ i++;
+ }
+
+ i++;
+ for (; i > 0; i --)
+ *dst++ = '\0';
+}
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
new file mode 100644
index 00000000..0787078a
--- /dev/null
+++ b/core/fs/pxe/dhcp_option.c
@@ -0,0 +1,270 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+char LocalDomain[256];
+
+int over_load;
+uint8_t uuid_type;
+char uuid[17];
+
+void parse_dhcp_options(void *, int, int);
+
+static void subnet_mask(void *data, int opt_len)
+{
+ if (opt_len != 4)
+ return;
+ net_mask = *(uint32_t *)data;
+}
+
+static void router(void *data, int opt_len)
+{
+ if (opt_len != 4)
+ return;
+ gate_way = *(uint32_t *)data;
+}
+
+static void dns_servers(void *data, int opt_len)
+{
+ int num = opt_len >> 2;
+ int i;
+
+ if (num > DNS_MAX_SERVERS)
+ num = DNS_MAX_SERVERS;
+
+ for (i = 0; i < num; i++) {
+ dns_server[i] = *(uint32_t *)data;
+ data += 4;
+ }
+
+#if 0
+ /*
+ * if you find you got no corret DNS server, you can add
+ * it here manually. BUT be carefull the DNS_MAX_SERVERS
+ */
+ if (i < DNS_MAX_SERVERS ) {
+ dns_server[i++] = your_master_dns_server;
+ dns_server[i++] = your_second_dns_server;
+ }
+#endif
+}
+
+static void local_domain(void *data, int opt_len)
+{
+ char *p = (char *)data + opt_len;
+ char *ld = LocalDomain;
+ char end = *p;
+
+ *p = '\0'; /* Zero-terminate option */
+ dns_mangle(&ld, data);
+ *p = end; /* Restore ending byte */
+}
+
+static void vendor_encaps(void *data, int opt_len)
+{
+ /* Only recongnize PXELINUX options */
+ parse_dhcp_options(data, opt_len, 208);
+}
+
+static void option_overload(void *data, int opt_len)
+{
+ if (opt_len != 1)
+ return;
+ over_load = *(uint8_t *)data;
+}
+
+
+static void server(void *data, int opt_len)
+{
+ uint32_t ip;
+
+ if (opt_len != 4)
+ return;
+
+ if (server_ip)
+ return;
+
+ ip = *(uint32_t *)data;
+ if (ip_ok(ip))
+ server_ip = ip;
+}
+
+static void client_identifier(void *data, int opt_len)
+{
+ if (opt_len > MAC_MAX || opt_len < 2 ||
+ MAC_len != (opt_len >> 8) ||
+ *(uint8_t *)data != MAC_type)
+ return;
+
+ opt_len --;
+ MAC_len = opt_len & 0xff;
+ memcpy(MAC, data+1, opt_len);
+ MAC[opt_len] = 0;
+}
+
+static void bootfile_name(void *data, int opt_len)
+{
+ strncpy(boot_file, data, opt_len);
+ boot_file[opt_len] = 0;
+}
+
+static void uuid_client_identifier(void *data, int opt_len)
+{
+ int type = *(uint8_t *)data;
+ if (opt_len != 17 ||
+ (type | have_uuid))
+ return;
+
+ have_uuid = 1;
+ uuid_type = type;
+ memcpy(uuid, data+1, 16);
+ uuid[16] = 0;
+}
+
+static void pxelinux_configfile(void *data, int opt_len)
+{
+ DHCPMagic |= 2;
+ strncpy(ConfigName, data, opt_len);
+ ConfigName[opt_len] = 0;
+}
+
+static void pxelinux_pathprefix(void *data,int opt_len)
+{
+ DHCPMagic |= 4;
+ strncpy(path_prefix, data, opt_len);
+ path_prefix[opt_len] = 0;
+}
+
+static void pxelinux_reboottime(void *data, int opt_len)
+{
+ if ((opt_len && 0xff) != 4)
+ return ;
+
+ RebootTime = ntohl(*(uint32_t *)data);
+ DHCPMagic |= 8; /* Got reboot time */
+}
+
+
+struct dhcp_options {
+ int opt_num;
+ void (*fun) (void *, int);
+};
+
+static struct dhcp_options dhcp_opts[] = {
+ {1, subnet_mask},
+ {3, router},
+ {6, dns_servers},
+ {15, local_domain},
+ {43, vendor_encaps},
+ {52, option_overload},
+ {54, server},
+ {61, client_identifier},
+ {67, bootfile_name},
+ {97, uuid_client_identifier},
+ {209, pxelinux_configfile},
+ {210, pxelinux_pathprefix},
+ {211, pxelinux_reboottime}
+};
+
+/*
+ * Parse a sequence of DHCP options, pointed to by _option_;
+ * -- some DHCP servers leave option fields unterminated
+ * in violation of the spec.
+ *
+ * filter contains the minimum value for the option to recognize
+ * -- this is used to restrict parsing to PXELINUX-specific options only.
+ */
+void parse_dhcp_options(void *option, int size, int filter)
+{
+ uint8_t opt_num;
+ uint8_t opt_len;
+ uint8_t opt_filter = filter == 208 ? 208 : 0;
+ int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]);
+ int i = 0;
+ char *p = option;
+ struct dhcp_options *opt;
+
+ if (opt_filter)
+ printf("***NOTE!:*** we hit a pxelinux-specific options\n");
+
+ while (size --) {
+ opt_num = *p++;
+
+ if (!size)
+ break;
+ if (opt_num == 0)
+ continue;
+ if (opt_num == 0xff)
+ break;
+
+ /* Anything else will have a lenght filed */
+ opt_len = *p++; /* c <- option lenght */
+ size = size - opt_len - 1;
+ if (size < 0)
+ break;
+ if (opt_num < opt_filter) { /* Is the option value valid */
+ option += opt_len; /* Try next */
+ continue;
+ }
+
+ opt = dhcp_opts;
+ for (i = 0; i < opt_entries; i++) {
+ if (opt_num == opt->opt_num) {
+ opt->fun(p, opt_len);
+ break;
+ }
+ opt ++;
+ }
+
+ /* parse next */
+ p += opt_len;
+ }
+}
+
+/*
+ * parse_dhcp
+ *
+ * Parse a DHCP packet. This includes dealing with "overloaded"
+ * option fields (see RFC 2132, section 9.3)
+ *
+ * This should fill in the following global variables, if the
+ * information is present:
+ *
+ * MyIP - client IP address
+ * server_ip - boot server IP address
+ * net_mask - network mask
+ * gate_way - default gateway router IP
+ * boot_file - boot file name
+ * DNSServers - DNS server IPs
+ * LocalDomain - Local domain name
+ * MAC_len, MAC - Client identifier, if MAC_len == 0
+ *
+ * This assumes the DHCP packet is in "trackbuf".
+ *
+ */
+void parse_dhcp(int pkt_len)
+{
+ struct bootp_t *dhcp = (struct bootp_t *)trackbuf;
+ int opt_len;
+
+ over_load = 0;
+ if (ip_ok(dhcp->yip))
+ MyIP = dhcp->yip;
+
+ if (ip_ok(dhcp->sip))
+ server_ip = dhcp->sip;
+
+ opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options;
+ if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC))
+ parse_dhcp_options(&dhcp->options, opt_len, 0);
+
+ if (over_load & 1)
+ parse_dhcp_options(&dhcp->bootfile, 128, 0);
+ else if (dhcp->bootfile[0])
+ strcpy(boot_file, dhcp->bootfile);
+
+ if (over_load & 2)
+ parse_dhcp_options(dhcp->sname, 64, 0);
+}
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
new file mode 100644
index 00000000..15560447
--- /dev/null
+++ b/core/fs/pxe/dnsresolv.c
@@ -0,0 +1,341 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include "pxe.h"
+
+/* DNS CLASS values we care about */
+#define CLASS_IN 1
+
+/* DNS TYPE values we care about */
+#define TYPE_A 1
+#define TYPE_CNAME 5
+
+/*
+ * The DNS header structure
+ */
+struct dnshdr {
+ uint16_t id;
+ uint16_t flags;
+ /* number of entries in the question section */
+ uint16_t qdcount;
+ /* number of resource records in the answer section */
+ uint16_t ancount;
+ /* number of name server resource records in the authority records section*/
+ uint16_t nscount;
+ /* number of resource records in the additional records section */
+ uint16_t arcount;
+} __attribute__ ((packed));
+
+/*
+ * The DNS query structure
+ */
+struct dnsquery {
+ uint16_t qtype;
+ uint16_t qclass;
+} __attribute__ ((packed));
+
+/*
+ * The DNS Resource recodes structure
+ */
+struct dnsrr {
+ uint16_t type;
+ uint16_t class;
+ uint32_t ttl;
+ uint16_t rdlength; /* The lenght of this rr data */
+ char rdata[];
+} __attribute__ ((packed));
+
+
+uint32_t dns_server[DNS_MAX_SERVERS] = {0, };
+
+
+/*
+ * Turn a string in _src_ into a DNS "label set" in _dst_; returns the
+ * number of dots encountered. On return, *dst is updated.
+ */
+int dns_mangle(char **dst, const char *p)
+{
+ char *q = *dst;
+ char *count_ptr;
+ char c;
+ int dots = 0;
+
+ count_ptr = q;
+ *q++ = 0;
+
+ while (1) {
+ c = *p++;
+ if (c == 0 || c == ':')
+ break;
+ if (c == '.') {
+ dots++;
+ count_ptr = q;
+ *q++ = 0;
+ continue;
+ }
+
+ *count_ptr += 1;
+ *q++ = c;
+ }
+
+ if (*count_ptr)
+ *q++ = 0;
+
+ /* update the strings */
+ *dst = q;
+ return dots;
+}
+
+
+/*
+ * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_
+ * is allowed pointers relative to a packet in buf.
+ *
+ */
+static bool dns_compare(const void *s1, const void *s2, const void *buf)
+{
+ const uint8_t *q = s1;
+ const uint8_t *p = s2;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ if (memcmp(q, p, c0))
+ return false;
+ q += c0;
+ p += c0;
+ } else {
+ return *q == 0;
+ }
+ }
+}
+
+/*
+ * Copy a DNS label into a buffer, considering the possibility that we might
+ * have to follow pointers relative to "buf".
+ * Returns a pointer to the first free byte *after* the terminal null.
+ */
+static void *dns_copylabel(void *dst, const void *src, const void *buf)
+{
+ uint8_t *q = dst;
+ const uint8_t *p = src;
+ unsigned int c0, c1;
+
+ while (1) {
+ c0 = p[0];
+ if (c0 >= 0xc0) {
+ /* Follow pointer */
+ c1 = p[1];
+ p = (const uint8_t *)buf + ((c0 - 0xc0) << 8) + c1;
+ } else if (c0) {
+ c0++; /* Include the length byte */
+ memcpy(q, p, c0);
+ p += c0;
+ q += c0;
+ } else {
+ *q++ = 0;
+ return q;
+ }
+ }
+}
+
+/*
+ * Skip past a DNS label set in DS:SI
+ */
+static char *dns_skiplabel(char *label)
+{
+ uint8_t c;
+
+ while (1) {
+ c = *label++;
+ if (c >= 0xc0)
+ return ++label; /* pointer is two bytes */
+ if (c == 0)
+ return label;
+ label += c;
+ }
+}
+
+/*
+ * Actual resolver function
+ * Points to a null-terminated or :-terminated string in _name_
+ * and returns the ip addr in _ip_ if it exists and can be found.
+ * If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
+ *
+ */
+uint32_t dns_resolv(const char *name)
+{
+ static char __lowmem DNSSendBuf[PKTBUF_SIZE];
+ static char __lowmem DNSRecvBuf[PKTBUF_SIZE];
+ char *p;
+ int err;
+ int dots;
+ int same;
+ int rd_len;
+ int ques, reps; /* number of questions and replies */
+ uint8_t timeout;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint32_t oldtime;
+ uint32_t srv;
+ uint32_t *srv_ptr = dns_server;
+ struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf;
+ struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf;
+ struct dnsquery *query;
+ struct dnsrr *rr;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+
+ /* First, fill the DNS header struct */
+ hd1->id++; /* New query ID */
+ hd1->flags = htons(0x0100); /* Recursion requested */
+ hd1->qdcount = htons(1); /* One question */
+ hd1->ancount = 0; /* No answers */
+ hd1->nscount = 0; /* No NS */
+ hd1->arcount = 0; /* No AR */
+
+ p = DNSSendBuf + sizeof(struct dnshdr);
+ dots = dns_mangle(&p, name); /* store the CNAME */
+
+ if (!dots) {
+ p--; /* Remove final null */
+ /* Uncompressed DNS label set so it ends in null */
+ strcpy(p, LocalDomain);
+ }
+
+ /* Fill the DNS query packet */
+ query = (struct dnsquery *)p;
+ query->qtype = htons(TYPE_A);
+ query->qclass = htons(CLASS_IN);
+ p += sizeof(struct dnsquery);
+
+ /* Now send it to name server */
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ while (srv_ptr < dns_server + DNS_MAX_SERVERS) {
+ srv = *srv_ptr++;
+ if (!srv)
+ continue; /* just move on before runing the time out */
+ udp_write.status = 0;
+ udp_write.ip = srv;
+ udp_write.gw = ((srv ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.src_port = DNS_LOCAL_PORT;
+ udp_write.dst_port = DNS_PORT;
+ udp_write.buffer_size = p - DNSSendBuf;
+ udp_write.buffer = FAR_PTR(DNSSendBuf);
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+ if (err || udp_write.status != 0)
+ continue;
+
+ oldtime = jiffies();
+ while (1) {
+ udp_read.status = 0;
+ udp_read.src_ip = srv;
+ udp_read.dest_ip = MyIP;
+ udp_read.s_port = DNS_PORT;
+ udp_read.d_port = DNS_LOCAL_PORT;
+ udp_read.buffer_size = DNS_MAX_PACKET;
+ udp_read.buffer = FAR_PTR(DNSRecvBuf);
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err || udp_read.status)
+ continue;
+
+ /* Got a packet, deal with it... */
+ if (hd2->id == hd1->id)
+ break;
+
+ if (jiffies()-oldtime >= timeout) {
+ /* time out */
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ return 0; /* All time ticks run out */
+ else
+ goto again;
+ }
+ }
+ if ((hd2->flags ^ 0x80) & htons(0xf80f))
+ goto badness;
+
+ ques = htons(hd2->qdcount); /* Questions */
+ reps = htons(hd2->ancount); /* Replies */
+ p = DNSRecvBuf + sizeof(struct dnshdr);
+ while (ques--) {
+ p = dns_skiplabel(p); /* Skip name */
+ p += 4; /* Skip question trailer */
+ }
+
+ /* Parse the replies */
+ while (reps--) {
+ same = dns_compare(DNSSendBuf + sizeof(struct dnshdr),
+ p, DNSRecvBuf);
+ p = dns_skiplabel(p);
+ rr = (struct dnsrr *)p;
+ rd_len = ntohs(rr->rdlength);
+ if (same && ntohs(rr->class) == CLASS_IN) {
+ switch (ntohs(rr->type)) {
+ case TYPE_A:
+ if (rd_len == 4)
+ return *(uint32_t *)rr->rdata;
+ break;
+ case TYPE_CNAME:
+ dns_copylabel(DNSSendBuf + sizeof(struct dnshdr),
+ rr->rdata, DNSRecvBuf);
+ /*
+ * We should probably rescan the packet from the top
+ * here, and technically we might have to send a whole
+ * new request here...
+ */
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* not the one we want, try next */
+ p += sizeof(struct dnsrr) + rd_len;
+ }
+
+ badness:
+ /*
+ *
+ ; We got back no data from this server.
+ ; Unfortunately, for a recursive, non-authoritative
+ ; query there is no such thing as an NXDOMAIN reply,
+ ; which technically means we can't draw any
+ ; conclusions. However, in practice that means the
+ ; domain doesn't exist. If this turns out to be a
+ ; problem, we may want to add code to go through all
+ ; the servers before giving up.
+
+ ; If the DNS server wasn't capable of recursion, and
+ ; isn't capable of giving us an authoritative reply
+ ; (i.e. neither AA or RA set), then at least try a
+ ; different setver...
+ */
+ if (hd2->flags == htons(0x480))
+ continue;
+
+ break; /* failed */
+
+ again:
+ continue;
+ }
+
+ return 0;
+}
+
+
+/*
+ * the one should be called from ASM file
+ */
+void pxe_dns_resolv(com32sys_t *regs)
+{
+ const char *name = MK_PTR(regs->ds, regs->esi.w[0]);
+
+ regs->eax.l = dns_resolv(name);
+}
diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c
new file mode 100644
index 00000000..5393ae1d
--- /dev/null
+++ b/core/fs/pxe/idle.c
@@ -0,0 +1,110 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 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
+ * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+static void pxe_idle_poll(void)
+{
+ static __lowmem char junk_pkt[PKTBUF_SIZE];
+ static __lowmem t_PXENV_UDP_READ read_buf;
+
+ memset(&read_buf, 0, sizeof read_buf);
+
+ read_buf.src_ip = 0; /* Any destination */
+ read_buf.dest_ip = MyIP;
+ read_buf.s_port = 0; /* Any source port */
+ read_buf.d_port = htons(9); /* Discard port (not used...) */
+ read_buf.buffer_size = sizeof junk_pkt;
+ read_buf.buffer = FAR_PTR(junk_pkt);
+
+ pxe_call(PXENV_UDP_READ, &read_buf);
+}
+
+static uint32_t pxe_detect_nic_type(void)
+{
+ static __lowmem t_PXENV_UNDI_GET_NIC_TYPE nic_type;
+
+ if (pxe_call(PXENV_UNDI_GET_NIC_TYPE, &nic_type))
+ return -1; /* Unknown NIC */
+
+ if (nic_type.NicType != PCI_NIC && nic_type.NicType != CardBus_NIC)
+ return -1; /* Not a PCI NIC */
+
+ /*
+ * Return VID:DID as a single number, with the VID in the high word
+ * -- this is opposite from the usual order, but it makes it easier to
+ * enforce that the table is sorted.
+ */
+ return (nic_type.info.pci.Vendor_ID << 16) + nic_type.info.pci.Dev_ID;
+}
+
+#define PCI_DEV(vid, did) (((vid) << 16) + (did))
+
+/* This array should be sorted!! */
+static const uint32_t pxe_need_idle_drain[] =
+{
+ /*
+ * Older Broadcom NICs: they need receive calls on idle to avoid
+ * FIFO stalls.
+ */
+ PCI_DEV(0x14e4, 0x1659), /* BCM5721 */
+ PCI_DEV(0x14e4, 0x165a), /* BCM5722 */
+ PCI_DEV(0x14e4, 0x165b), /* BCM5723 */
+ PCI_DEV(0x14e4, 0x1668), /* BCM5714 */
+ PCI_DEV(0x14e4, 0x1669), /* BCM5714S */
+ PCI_DEV(0x14e4, 0x166a), /* BCM5780 */
+ PCI_DEV(0x14e4, 0x1673), /* BCM5755M */
+ PCI_DEV(0x14e4, 0x1674), /* BCM5756ME */
+ PCI_DEV(0x14e4, 0x1678), /* BCM5715 */
+ PCI_DEV(0x14e4, 0x1679), /* BCM5715S */
+ PCI_DEV(0x14e4, 0x167b), /* BCM5755 */
+};
+
+void pxe_idle_init(void)
+{
+ uint32_t dev_id = pxe_detect_nic_type();
+ int l, h;
+ bool found;
+
+ l = 0;
+ h = sizeof pxe_need_idle_drain / sizeof pxe_need_idle_drain[0] - 1;
+
+ found = false;
+ while (h >= l) {
+ int x = (l+h) >> 1;
+ uint32_t id = pxe_need_idle_drain[x];
+
+ if (id == dev_id) {
+ found = true;
+ break;
+ } else if (id < dev_id) {
+ l = x+1;
+ } else {
+ h = x-1;
+ }
+ }
+
+ if (found)
+ idle_hook_func = pxe_idle_poll;
+}
+
+void pxe_idle_cleanup(void)
+{
+ idle_hook_func = NULL;
+}
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
new file mode 100644
index 00000000..1bbb6b0a
--- /dev/null
+++ b/core/fs/pxe/pxe.c
@@ -0,0 +1,1576 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+#include <minmax.h>
+#include <sys/cpu.h>
+#include "pxe.h"
+
+#define GPXE 1
+
+uint32_t server_ip = 0; /* IP address of boot server */
+uint32_t net_mask = 0; /* net_mask of this subnet */
+uint32_t gate_way = 0; /* Default router */
+uint16_t server_port = TFTP_PORT; /* TFTP server port */
+uint16_t real_base_mem; /* Amount of DOS memory after freeing */
+
+char MAC_str[3 * (MAC_MAX + 1)]; /* MAC address as a string */
+char MAC[MAC_MAX + 1]; /* Actual MAC address */
+uint8_t MAC_len; /* MAC address len */
+uint8_t MAC_type; /* MAC address type */
+
+char boot_file[256];
+char path_prefix[256];
+char dot_quad_buf[16];
+
+static struct open_file_t Files[MAX_OPEN];
+static int has_gpxe;
+static uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0};
+int have_uuid = 0;
+
+const uint8_t TimeoutTable[] = {
+ 2, 2, 3, 3, 4, 5, 6, 7, 9, 10, 12, 15, 18, 21, 26, 31, 37, 44, 53, 64, 77,
+ 92, 110, 132, 159, 191, 229, 255, 255, 255, 255, 0
+};
+
+/* PXE unload sequences */
+const uint8_t new_api_unload[] = {
+ PXENV_UDP_CLOSE, PXENV_UNDI_SHUTDOWN,
+ PXENV_UNLOAD_STACK, PXENV_STOP_UNDI, 0
+};
+const uint8_t old_api_unload[] = {
+ PXENV_UDP_CLOSE, PXENV_UNDI_SHUTDOWN,
+ PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0
+};
+
+struct tftp_options {
+ const char *str_ptr; /* string pointer */
+ size_t offset; /* offset into socket structre */
+};
+static const struct tftp_options tftp_options[] =
+{
+ { "tsize", offsetof(struct open_file_t, tftp_filesize) },
+ { "blksize", offsetof(struct open_file_t, tftp_blksize) },
+};
+static const int tftp_nopts = sizeof tftp_options / sizeof tftp_options[0];
+
+static void tftp_error(struct open_file_t *file, uint16_t errnum,
+ const char *errstr);
+
+/*
+ * Initialize the Files structure
+ */
+static void files_init(void)
+{
+ int i;
+ struct open_file_t *socket = Files;
+ uint16_t pktbuf = 0;
+ uint16_t nextport = 49152;
+
+ for (i = 0; i < MAX_OPEN; i++) {
+ socket->tftp_pktbuf = pktbuf;
+ socket->tftp_nextport = nextport;
+ pktbuf += PKTBUF_SIZE;
+ nextport++;
+ socket++;
+ }
+}
+
+/*
+ * Allocate a local UDP port structure.
+ * return the socket pointer if success, or null if failure
+ *
+ */
+static struct open_file_t *allocate_socket(void)
+{
+ int i;
+ struct open_file_t *socket = Files;
+ uint16_t nextport;
+
+ for (i = 0; i < MAX_OPEN; i++) {
+ if (!socket->tftp_localport)
+ break;
+ socket++;
+ }
+
+ if (i == MAX_OPEN)
+ return NULL;
+
+ /*
+ * Allocate a socket number. Socket numbers are made guaranteed
+ * unique by including the socket slot number; add a counter value
+ * to keep the numbers from being likely to get immediately
+ * reused. The mask enforces wraparound to the range 49152-57343.
+ */
+ nextport = socket->tftp_nextport;
+ socket->tftp_nextport = (nextport + (1 << MAX_OPEN_LG2)) & 0xdfff;
+ socket->tftp_localport = htons(nextport); /* Socket now in use */
+ return socket;
+}
+
+/*
+ * free socket in _file_.
+ */
+static void free_socket(struct open_file_t *file)
+{
+ /* tftp_nextport and tftp_pktbuf are not cleared */
+ memset(file, 0, offsetof(struct open_file_t, tftp_nextport));
+}
+
+static void pxe_close_file(struct file *file)
+{
+ struct open_file_t *open_file = file->open_file;
+
+ if (open_file->tftp_localport && !open_file->tftp_goteof)
+ tftp_error(open_file, 0, "No error, file close");
+
+ free_socket(open_file);
+}
+
+/**
+ * Take a nubmer of bytes in memory and convert to lower-case hxeadecimal
+ *
+ * @param: dst, output buffer
+ * @param: src, input buffer
+ * @param: count, number of bytes
+ *
+ */
+static void lchexbytes(char *dst, const void *src, int count)
+{
+ uint8_t half;
+ uint8_t c;
+ const uint8_t *s = src;
+
+ for(; count > 0; count--) {
+ c = *s++;
+ half = ((c >> 4) & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
+
+ half = (c & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'a' - '9' - 1) : half;
+ }
+}
+
+/*
+ * just like the lchexbytes, except to upper-case
+ *
+ */
+static void uchexbytes(char *dst, const void *src, int count)
+{
+ uint8_t half;
+ uint8_t c;
+ const uint8_t *s = src;
+
+ for(; count > 0; count--) {
+ c = *s++;
+ half = ((c >> 4) & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
+
+ half = (c & 0x0f) + '0';
+ *dst++ = half > '9' ? (half + 'A' - '9' - 1) : half;
+ }
+}
+
+/*
+ * Tests an IP address in _ip_ for validity; return with 0 for bad, 1 for good.
+ * We used to refuse class E, but class E addresses are likely to become
+ * assignable unicast addresses in the near future.
+ *
+ */
+int ip_ok(uint32_t ip)
+{
+ if (ip == -1 || /* Refuse the all-one address */
+ (ip & 0xff) == 0 || /* Refuse network zero */
+ (ip & 0xff) == 0xff || /* Refuse loopback */
+ (ip & 0xf0) == 0xe0 ) /* Refuse class D */
+ return 0;
+
+ return 1;
+}
+
+
+/*
+ * Take an IP address (in network byte order) in _ip_ and
+ * output a dotted quad string to _dst_, returns the length
+ * of the dotted quad ip string.
+ *
+ */
+static int gendotquad(char *dst, uint32_t ip)
+{
+ int part;
+ int i = 0, j;
+ char temp[4];
+ char *p = dst;
+
+ for (; i < 4; i++) {
+ j = 0;
+ part = ip & 0xff;
+ do {
+ temp[j++] = (part % 10) + '0';
+ }while(part /= 10);
+ for (; j > 0; j--)
+ *p++ = temp[j-1];
+ *p++ = '.';
+
+ ip >>= 8;
+ }
+ /* drop the last dot '.' and zero-terminate string*/
+ *(--p) = 0;
+
+ return p - dst;
+}
+
+/*
+ * parse the ip_str and return the ip address with *res.
+ * return the the string address after the ip string
+ *
+ */
+static const char *parse_dotquad(const char *ip_str, uint32_t *res)
+{
+ const char *p = ip_str;
+ int i = 0;
+ uint8_t part = 0;
+ uint32_t ip = 0;
+
+ for (; i < 4; i++) {
+ while (is_digit(*p)) {
+ part = part * 10 + *p - '0';
+ p++;
+ }
+ if (i != 3 && *p != '.')
+ return NULL;
+
+ ip = (ip << 8) | part;
+ part = 0;
+ p++;
+ }
+ p --;
+
+ *res = ip;
+ return p;
+}
+
+/*
+ * the ASM pxenv function wrapper, return 1 if error, or 0
+ *
+ */
+int pxe_call(int opcode, void *data)
+{
+ extern void pxenv(void);
+ com32sys_t regs;
+
+#if 0
+ printf("pxe_call op %04x data %p\n", opcode, data);
+#endif
+
+ memset(&regs, 0, sizeof regs);
+ regs.ebx.w[0] = opcode;
+ regs.es = SEG(data);
+ regs.edi.w[0] = OFFS(data);
+ call16(pxenv, &regs, &regs);
+
+ return regs.eflags.l & EFLAGS_CF; /* CF SET if fail */
+}
+
+/**
+ * Send an ERROR packet. This is used to terminate a connection.
+ *
+ * @file: TFTP file pointer
+ * @errnum: Error number (network byte order)
+ * @errstr: Error string (included in packet)
+ */
+static void tftp_error(struct open_file_t *file, uint16_t errnum,
+ const char *errstr)
+{
+ static __lowmem struct {
+ uint16_t err_op;
+ uint16_t err_num;
+ char err_msg[64];
+ } __packed err_buf;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ int len = min(strlen(errstr), sizeof(err_buf.err_msg)-1);
+
+ err_buf.err_op = TFTP_ERROR;
+ err_buf.err_num = errnum;
+ memcpy(err_buf.err_msg, errstr, len);
+ err_buf.err_msg[len] = '\0';
+
+ udp_write.src_port = file->tftp_localport;
+ udp_write.dst_port = file->tftp_remoteport;
+ udp_write.ip = file->tftp_remoteip;
+ udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.buffer = FAR_PTR(&err_buf);
+ udp_write.buffer_size = 4 + len + 1;
+
+ /* If something goes wrong, there is nothing we can do, anyway... */
+ pxe_call(PXENV_UDP_WRITE, &udp_write);
+}
+
+
+/**
+ * Send ACK packet. This is a common operation and so is worth canning.
+ *
+ * @param: file, TFTP block pointer
+ * @param: ack_num, Packet # to ack (network byte order)
+ *
+ */
+static void ack_packet(struct open_file_t *file, uint16_t ack_num)
+{
+ int err;
+ static __lowmem uint16_t ack_packet_buf[2];
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+
+ /* Packet number to ack */
+ ack_packet_buf[0] = TFTP_ACK;
+ ack_packet_buf[1] = ack_num;
+ udp_write.src_port = file->tftp_localport;
+ udp_write.dst_port = file->tftp_remoteport;
+ udp_write.ip = file->tftp_remoteip;
+ udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.buffer = FAR_PTR(ack_packet_buf);
+ udp_write.buffer_size = 4;
+
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+#if 0
+ printf("sent %s\n", err ? "FAILED" : "OK");
+#endif
+}
+
+
+/**
+ * Get a DHCP packet from the PXE stack into the trackbuf
+ *
+ * @param: type, packet type
+ * @return: buffer size
+ *
+ */
+static int pxe_get_cached_info(int type)
+{
+ int err;
+ static __lowmem struct s_PXENV_GET_CACHED_INFO get_cached_info;
+ printf(" %02x", type);
+
+ get_cached_info.Status = 0;
+ get_cached_info.PacketType = type;
+ get_cached_info.BufferSize = 8192;
+ get_cached_info.Buffer = FAR_PTR(trackbuf);
+ err = pxe_call(PXENV_GET_CACHED_INFO, &get_cached_info);
+ if (err) {
+ printf("PXE API call failed, error %04x\n", err);
+ kaboom();
+ }
+
+ return get_cached_info.BufferSize;
+}
+
+
+
+#if GPXE
+
+/*
+ * Return 1 if and only if the buffer pointed to by
+ * url is a URL (contains ://)
+ *
+ */
+static int is_url(const char *url)
+{
+ while (*url) {
+ if (!strncmp(url, "://", 3))
+ return 1;
+
+ url++;
+ }
+ return 0;
+}
+
+
+/*
+ * Return CF=0 if and only if the buffer pointed to by DS:SI is a URL
+ * (contains ://) *and* the gPXE extensions API is available. No
+ * registers modified.
+ */
+static int is_gpxe(char *url)
+{
+ int err;
+ static __lowmem struct s_PXENV_FILE_API_CHECK api_check;
+ char *gpxe_warning_msg =
+ "URL syntax, but gPXE extensions not detected, tring plain TFTP...\n";
+
+ if (! is_url(url))
+ return 0;
+
+ api_check.Size = sizeof api_check;
+ api_check.Magic = 0x91d447b2;
+ /* If has_gpxe is greater than one, means the gpxe status is unknow */
+ while (has_gpxe > 1) {
+ err = pxe_call(PXENV_FILE_API_CHECK, &api_check);
+ if (err || api_check.Magic != 0xe9c17b20)
+ printf("%s\n", gpxe_warning_msg);
+ else
+ has_gpxe = (~api_check.Provider & 0xffff) & 0x4b ? 0 : 1;
+
+ if (!has_gpxe)
+ printf("%s\n", gpxe_warning_msg);
+ }
+
+ return has_gpxe == 1;
+}
+
+/**
+ * Get a fresh packet from a gPXE socket
+ * @param: file -> socket structure
+ *
+ */
+static void get_packet_gpxe(struct open_file_t *file)
+{
+ static __lowmem struct s_PXENV_FILE_READ file_read;
+ int err;
+
+ while (1) {
+ file_read.FileHandle = file->tftp_remoteport;
+ file_read.Buffer.offs = file->tftp_pktbuf;
+ file_read.Buffer.seg = PKTBUF_SEG;
+ file_read.BufferSize = PKTBUF_SIZE;
+ err = pxe_call(PXENV_FILE_READ, &file_read);
+ if (!err) /* successed */
+ break;
+
+ if (file_read.Status != PXENV_STATUS_TFTP_OPEN)
+ kaboom();
+ }
+
+ file->tftp_bytesleft = file_read.BufferSize;
+ file->tftp_filepos += file_read.BufferSize;
+
+ if (file->tftp_bytesleft == 0)
+ file->tftp_filesize = file->tftp_filepos;
+
+ /* if we're done here, close the file */
+ if (file->tftp_filesize > file->tftp_filepos)
+ return;
+
+ /* Got EOF, close it */
+ file->tftp_goteof = 1;
+ pxe_call(PXENV_FILE_CLOSE, &file_read);
+}
+#endif /* GPXE */
+
+
+/*
+ * mangle a filename pointed to by _src_ into a buffer pointed
+ * to by _dst_; ends on encountering any whitespace.
+ *
+ * The first four bytes of the manged name is the IP address of
+ * the download host, 0 for no host, or -1 for a gPXE URL.
+ *
+ */
+static void pxe_mangle_name(char *dst, const char *src)
+{
+ const char *p = src;
+ uint32_t ip = server_ip;
+ int i = 0;
+
+#if GPXE
+ if (is_url(src)) {
+ ip = -1;
+ goto store;
+ }
+#endif
+
+ if (*p == 0 || !(p = strstr(src, "::"))) {
+ /* seems no ip, so make ip to 0 */
+ p = src;
+ ip = 0;
+ } else if (p == src) {
+ /* skip the first two-colon */
+ p += 2;
+ } else {
+ /*
+ * we have a :: prefix of some sort, it could be either a DNS
+ * name or dot-quad IP address. Try the dot-quad first.
+ */
+ p = src;
+ if ((p = parse_dotquad(p, &ip)) && !strncmp(p, "::", 2)) {
+ p += 2;
+ } else {
+ ip = dns_resolv(p);
+ if (ip && (p = strchr(p, ':')) && p[1] == ':') {
+ p += 2;
+ } else {
+ /* no ip, too */
+ p = src;
+ ip = 0;
+ }
+ }
+ }
+
+ store:
+ *(uint32_t *)dst = ip;
+ dst += 4;
+ i = FILENAME_MAX - 5;
+
+ do {
+ if (!not_whitespace(*p))
+ break;
+ *dst++ = *p++;
+ } while (i--);
+
+ i++;
+ while (i) {
+ *dst++ = 0;
+ i--;
+ }
+}
+
+
+/*
+ * Does the opposite of mangle_name; converts a DOS-mangled
+ * filename to the conventional representation. This is
+ * needed for the BOOT_IMAGE= parameter for the kernel.
+ */
+static char *pxe_unmangle_name(char *dst, const char *src)
+{
+ uint32_t ip = *(uint32_t *)src;
+ int ip_len = 0;
+
+ if (ip != 0 && ip != -1) {
+ ip_len = gendotquad(dst, *(uint32_t *)src);
+ dst += ip_len;
+ }
+ src += 4;
+ return stpcpy(dst, src);
+}
+
+/*
+ * Get a fresh packet if the buffer is drained, and we haven't hit
+ * EOF yet. The buffer should be filled immediately after draining!
+ */
+static void fill_buffer(struct open_file_t *file)
+{
+ int err;
+ int last_pkt;
+ const uint8_t *timeout_ptr = TimeoutTable;
+ uint8_t timeout;
+ uint16_t buffersize;
+ uint32_t oldtime;
+ void *data = NULL;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+
+ if (file->tftp_bytesleft || file->tftp_goteof)
+ return;
+
+#if GPXE
+ if (file->tftp_localport == 0xffff) {
+ get_packet_gpxe(file);
+ return;
+ }
+#endif
+
+
+ /*
+ * Start by ACKing the previous packet; this should cause
+ * the next packet to be sent.
+ */
+ ack_again:
+ ack_packet(file, file->tftp_lastpkt);
+
+ timeout_ptr = TimeoutTable;
+ timeout = *timeout_ptr++;
+ oldtime = jiffies();
+ while (timeout) {
+ udp_read.buffer.offs = file->tftp_pktbuf;
+ udp_read.buffer.seg = PKTBUF_SEG;
+ udp_read.buffer_size = PKTBUF_SIZE;
+ udp_read.src_ip = file->tftp_remoteip;
+ udp_read.dest_ip = MyIP;
+ udp_read.s_port = file->tftp_remoteport;
+ udp_read.d_port = file->tftp_localport;
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err) {
+ uint32_t now = jiffies();
+
+ if (now-oldtime >= timeout) {
+ oldtime = now;
+ timeout = *timeout_ptr++;
+ if (!timeout)
+ break;
+ }
+ continue;
+ }
+
+ if (udp_read.buffer_size < 4) /* Bad size for a DATA packet */
+ continue;
+
+ data = MK_PTR(PKTBUF_SEG, file->tftp_pktbuf);
+ if (*(uint16_t *)data != TFTP_DATA) /* Not a data packet */
+ continue;
+
+ /* If goes here, recevie OK, break */
+ break;
+ }
+
+ /* time runs out */
+ if (timeout == 0)
+ kaboom();
+
+ last_pkt = file->tftp_lastpkt;
+ last_pkt = ntohs(last_pkt); /* Host byte order */
+ last_pkt++;
+ last_pkt = htons(last_pkt); /* Network byte order */
+ if (*(uint16_t *)(data + 2) != last_pkt) {
+ /*
+ * Wrong packet, ACK the packet and try again.
+ * This is presumably because the ACK got lost,
+ * so the server just resent the previous packet.
+ */
+#if 0
+ printf("Wrong packet, wanted %04x, got %04x\n", \
+ htons(last_pkt), htons(*(uint16_t *)(data+2)));
+#endif
+ goto ack_again;
+ }
+
+ /* It's the packet we want. We're also EOF if the size < blocksize */
+ file->tftp_lastpkt = last_pkt; /* Update last packet number */
+ buffersize = udp_read.buffer_size - 4; /* Skip TFTP header */
+ file->tftp_dataptr = file->tftp_pktbuf + 4;
+ file->tftp_filepos += buffersize;
+ file->tftp_bytesleft = buffersize;
+ if (buffersize < file->tftp_blksize) {
+ /* it's the last block, ACK packet immediately */
+ ack_packet(file, *(uint16_t *)(data + 2));
+
+ /* Make sure we know we are at end of file */
+ file->tftp_filesize = file->tftp_filepos;
+ file->tftp_goteof = 1;
+ }
+}
+
+
+/**
+ * getfssec: Get multiple clusters from a file, given the starting cluster.
+ * In this case, get multiple blocks from a specific TCP connection.
+ *
+ * @param: fs, the fs_info structure address, in pxe, we don't use this.
+ * @param: buf, buffer to store the read data
+ * @param: openfile, TFTP socket pointer
+ * @param: blocks, 512-byte block count; 0FFFFh = until end of file
+ *
+ * @return: the bytes read
+ *
+ */
+static uint32_t pxe_getfssec(struct file *gfile, char *buf,
+ int blocks, bool *have_more)
+{
+ struct open_file_t *file = gfile->open_file;
+ int count = blocks;
+ int chunk;
+ int bytes_read = 0;
+
+ count <<= TFTP_BLOCKSIZE_LG2;
+ while (count) {
+ fill_buffer(file); /* If we have no 'fresh' buffer, get it */
+ if (!file->tftp_bytesleft)
+ break;
+
+ chunk = count;
+ if (chunk > file->tftp_bytesleft)
+ chunk = file->tftp_bytesleft;
+ file->tftp_bytesleft -= chunk;
+ memcpy(buf, MK_PTR(PKTBUF_SEG, file->tftp_dataptr), chunk);
+ file->tftp_dataptr += chunk;
+ buf += chunk;
+ bytes_read += chunk;
+ count -= chunk;
+ }
+
+
+ if (file->tftp_bytesleft || (file->tftp_filepos < file->tftp_filesize)) {
+ fill_buffer(file);
+ *have_more = 1;
+ } else if (file->tftp_goteof) {
+ /*
+ * The socket is closed and the buffer drained; the caller will
+ * call close_file and therefore free the socket.
+ */
+ *have_more = 0;
+ }
+
+ return bytes_read;
+ }
+
+
+
+/*
+ * Fill the packet tail with the tftp informations then retures the lenght
+ */
+static int fill_tail(char *dst)
+{
+ static const char tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
+
+ memcpy(dst, tail, sizeof tail);
+ return sizeof tail;
+}
+
+
+/**
+ * Open a TFTP connection to the server
+ *
+ * @param:filename, the file we wanna open
+ *
+ * @out: open_file_t structure, stores in file->open_file
+ * @ouT: the lenght of this file, stores in file->file_len
+ *
+ */
+static void pxe_searchdir(char *filename, struct file *file)
+{
+ char *buf = packet_buf;
+ char *p = filename;
+ char *options;
+ char *data;
+ struct open_file_t *open_file;
+ static __lowmem struct s_PXENV_UDP_WRITE udp_write;
+ static __lowmem struct s_PXENV_UDP_READ udp_read;
+ static __lowmem struct s_PXENV_FILE_OPEN file_open;
+ static __lowmem struct s_PXENV_GET_FILE_SIZE get_file_size;
+ const struct tftp_options *tftp_opt;
+ int i = 0;
+ int err;
+ int buffersize;
+ const uint8_t *timeout_ptr;
+ uint8_t timeout;
+ uint32_t oldtime;
+ uint16_t tid;
+ uint16_t opcode;
+ uint16_t blk_num;
+ uint32_t ip;
+ uint32_t opdata, *opdata_ptr;
+
+ open_file = allocate_socket();
+ if (!open_file) {
+ file->file_len = 0;
+ file->open_file = NULL;
+ return;
+ }
+
+ timeout_ptr = TimeoutTable; /* Reset timeout */
+
+ sendreq:
+ udp_write.buffer.offs = OFFS_WRT(buf, 0);
+ udp_write.buffer.seg = 0;
+ *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
+ buf += 2;
+
+ ip = *(uint32_t *)p; /* ip <- server override (if any) */
+ p += 4;
+ if (ip == 0) {
+ /* Have prefix */
+ strcpy(buf, path_prefix);
+ buf += strlen(path_prefix);
+ ip = server_ip; /* Get the default server */
+ }
+
+ strcpy(buf, p); /* Copy the filename */
+ buf += strlen(p) + 1; /* advance the pointer, null char included */
+
+#if GPXE
+ if (is_gpxe(packet_buf + 2)) {
+ file_open.Status = PXENV_STATUS_BAD_FUNC;
+ file_open.FileName.offs = OFFS_WRT(packet_buf + 2, 0);
+ file_open.FileName.seg = 0;
+ err = pxe_call(PXENV_FILE_OPEN, &file_open);
+ if (err)
+ goto done;
+
+ open_file->tftp_localport = -1;
+ open_file->tftp_remoteport = file_open.FileHandle;
+ get_file_size.FileHandle = file_open.FileHandle;
+
+#if 0
+ err = pxe_call(PXENV_GET_FILE_SIZE, &get_file_size);
+ if (!err)
+ open_file->tftp_filesize = get_file_size.FileSize;
+ else
+#endif
+ open_file->tftp_filesize = -1;
+ goto done;
+ }
+#endif /* GPXE */
+
+ open_file->tftp_remoteip = ip;
+ tid = open_file->tftp_localport; /* TID(local port No) */
+ udp_write.ip = ip;
+ udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
+ udp_write.src_port = tid;
+ udp_write.dst_port = server_port;
+ buf += fill_tail(buf);
+ udp_write.buffer_size = buf - packet_buf;
+ err = pxe_call(PXENV_UDP_WRITE, &udp_write);
+ if (err || udp_write.status != 0)
+ goto failure; /*
+ * In fact, the 'failure' target will not do
+ * a failure thing; it will move on to the
+ * next timeout, then tries again until
+ * _real_ time out
+ */
+
+ /*
+ * Danger, Will Robinson! We need to support tiemout
+ * and retry lest we just lost a packet ...
+ */
+
+ /* Packet transmitted OK, now we need to receive */
+ timeout = *timeout_ptr++;
+ oldtime = jiffies();
+ for (;;) {
+ buf = packet_buf;
+ udp_read.buffer.offs = OFFS_WRT(buf, 0);
+ udp_read.buffer.seg = 0;
+ udp_read.buffer_size = 2048;
+ udp_read.dest_ip = MyIP;
+ udp_read.d_port = tid;
+ err = pxe_call(PXENV_UDP_READ, &udp_read);
+ if (err) {
+ uint32_t now = jiffies();
+ if (now-oldtime >= timeout)
+ goto failure;
+ continue;
+ }
+
+ /* Make sure the packet actually came from the server */
+ if (udp_read.src_ip == open_file->tftp_remoteip)
+ break;
+ }
+
+ /* Got packet; reset timeout */
+ timeout_ptr = TimeoutTable;
+ open_file->tftp_remoteport = udp_read.s_port;
+
+ /* filesize <- -1 == unknown */
+ open_file->tftp_filesize = -1;
+ /* Default blksize unless blksize option negotiated */
+ open_file->tftp_blksize = TFTP_BLOCKSIZE;
+ buffersize = udp_read.buffer_size - 2; /* bytes after opcode */
+ if (buffersize < 0)
+ goto failure; /* Garbled reply */
+
+ /*
+ * Get the opcode type, and parse it
+ */
+ opcode = *(uint16_t *)packet_buf;
+ switch (opcode) {
+ case TFTP_ERROR:
+ open_file->tftp_filesize = 0;
+ break; /* ERROR reply; don't try again */
+
+ case TFTP_DATA:
+ /*
+ * 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...
+ *
+ * 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...
+ */
+ buffersize -= 2;
+ if (buffersize < 0)
+ goto failure;
+ data = packet_buf + 2;
+ blk_num = *(uint16_t *)data;
+ data += 2;
+ if (blk_num != htons(1))
+ goto failure;
+ open_file->tftp_lastpkt = blk_num;
+ if (buffersize > TFTP_BLOCKSIZE)
+ goto err_reply; /* Corrupt */
+ else if (buffersize < TFTP_BLOCKSIZE) {
+ /*
+ * This is the final EOF packet, already...
+ * We know the filesize, but we also want to
+ * ack the packet and set the EOF flag.
+ */
+ open_file->tftp_filesize = buffersize;
+ open_file->tftp_goteof = 1;
+ ack_packet(open_file, blk_num);
+ }
+
+ open_file->tftp_bytesleft = buffersize;
+ open_file->tftp_dataptr = open_file->tftp_pktbuf;
+ memcpy(MK_PTR(PKTBUF_SEG, open_file->tftp_pktbuf), data, buffersize);
+ break;
+
+ case TFTP_OACK:
+ /*
+ * Now we need to parse the OACK packet to get the transfer
+ * and packet sizes.
+ */
+
+ options = packet_buf + 2;
+ p = options;
+
+ while (buffersize) {
+ char *opt = p;
+
+ /*
+ * If we find an option which starts with a NUL byte,
+ * (a null option), we're either seeing garbage that some
+ * TFTP servers add to the end of the packet, or we have
+ * no clue how to parse the rest of the packet (what is
+ * an option name and what is a value?) In either case,
+ * discard the rest.
+ */
+ if (!*opt)
+ goto done;
+
+ while (buffersize) {
+ if (!*p)
+ break; /* Found a final null */
+ *p++ |= 0x20;
+ buffersize--;
+ }
+ if (!buffersize)
+ break; /* Unterminated option */
+
+ /* Consume the terminal null */
+ p++;
+ buffersize--;
+
+ if (!buffersize)
+ break; /* No option data */
+
+ /*
+ * Parse option pointed to by options; guaranteed to be
+ * null-terminated
+ */
+ tftp_opt = tftp_options;
+ for (i = 0; i < tftp_nopts; i++) {
+ if (!strcmp(opt, tftp_opt->str_ptr))
+ break;
+ tftp_opt++;
+ }
+ if (i == tftp_nopts)
+ goto err_reply; /* Non-negotitated option returned,
+ no idea what it means ...*/
+
+ /* get the address of the filed that we want to write on */
+ opdata_ptr = (uint32_t *)((char *)open_file + tftp_opt->offset);
+ opdata = 0;
+
+ /* do convert a number-string to decimal number, just like atoi */
+ while (buffersize--) {
+ uint8_t d = *p++;
+ if (d == '\0')
+ break; /* found a final null */
+ d -= '0';
+ if (d > 9)
+ goto err_reply; /* Not a decimal digit */
+ opdata = opdata*10 + d;
+ }
+ *opdata_ptr = opdata;
+ }
+ break;
+
+ default:
+ printf("TFTP unknown opcode %d\n", ntohs(opcode));
+ goto err_reply;
+ }
+
+done:
+ if (!open_file->tftp_filesize) {
+ free_socket(open_file);
+ file->file_len = 0;
+ file->open_file = NULL;
+ return;
+ }
+ file->open_file = (void *)open_file;
+ file->file_len = open_file->tftp_filesize;
+ return;
+
+err_reply:
+ /* Build the TFTP error packet */
+ tftp_error(open_file, TFTP_EOPTNEG, "TFTP protocol error");
+ printf("TFTP server sent an incomprehesible reply\n");
+ kaboom();
+
+failure:
+ timeout_ptr++;
+ if (*timeout_ptr)
+ goto sendreq; /* Try again */
+}
+
+
+/*
+ * Store standard filename prefix
+ */
+static void get_prefix(void)
+{
+ int len;
+ char *p;
+ char c;
+
+ if (DHCPMagic & 0x04) /* Did we get a path prefix option */
+ goto got_prefix;
+
+ strcpy(path_prefix, boot_file);
+ len = strlen(path_prefix);
+ p = &path_prefix[len - 1];
+
+ while (len--) {
+ c = *p--;
+ c |= 0x20;
+
+ c = (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '.' || c == '-');
+ if (!c)
+ break;
+ };
+
+ if (len < 0)
+ p --;
+
+ *(p + 2) = 0; /* Zero-terminate after delimiter */
+
+ got_prefix:
+ printf("TFTP prefix: %s\n", path_prefix);
+ strcpy(CurrentDirName, path_prefix);
+}
+
+ /*
+ * try to load a config file, if found, return 1, or return 0
+ *
+ */
+static int try_load(char *config_name)
+{
+ com32sys_t regs;
+
+ printf("Trying to load: %-50s ", config_name);
+ pxe_mangle_name(KernelName, config_name);
+
+ memset(&regs, 0, sizeof regs);
+ regs.edi.w[0] = OFFS_WRT(KernelName, 0);
+ call16(core_open, &regs, &regs);
+ if (regs.eflags.l & EFLAGS_ZF) {
+ printf(" [FAILED]\n");
+ return 0;
+ } else {
+ printf(" [ OK ]\n");
+ return 1;
+ }
+}
+
+
+/* Load the config file, return 1 if failed, or 0 */
+static int pxe_load_config(void)
+{
+ const char *cfgprefix = "pxelinux.cfg/";
+ const char *default_str = "default";
+ char *config_file;
+ char *last;
+ char *p;
+ uint8_t *uuid_ptr;
+ int tries = 8;
+
+ get_prefix();
+ if (DHCPMagic & 0x02) {
+ /* We got a DHCP option, try it first */
+ if (try_load(boot_file))
+ return 0;
+ }
+
+ /*
+ * Have to guess config file name ...
+ */
+ memcpy(ConfigName, cfgprefix, strlen(cfgprefix));
+ config_file = ConfigName + strlen(cfgprefix);
+
+ /* Try loading by UUID */
+ if (have_uuid) {
+ uuid_ptr = uuid_dashes;
+ p = config_file;
+ while (*uuid_ptr) {
+ int len = *uuid_ptr;
+ char *src = uuid;
+
+ lchexbytes(p, src, len);
+ p += len * 2;
+ src += len;
+ uuid_ptr++;
+ *p++ = '-';
+ }
+ /* Remove last dash and zero-terminate */
+ *--p = '\0';
+ if (try_load(ConfigName))
+ return 0;
+ }
+
+ /* Try loading by MAC address */
+ strcpy(config_file, MAC_str);
+ if (try_load(ConfigName))
+ return 0;
+
+ /* Nope, try hexadecimal IP prefixes... */
+ uchexbytes(config_file, (uint8_t *)&MyIP, 4); /* Convet to hex string */
+ last = &config_file[8];
+ while (tries) {
+ *last = '\0'; /* Zero-terminate string */
+ if (try_load(ConfigName))
+ return 0;
+ last--; /* Drop one character */
+ tries--;
+ };
+
+ /* Final attempt: "default" string */
+ strcpy(config_file, default_str);
+ if (try_load(ConfigName))
+ return 0;
+
+ printf("Unable to locate configuration file\n");
+ kaboom();
+}
+
+/*
+ * Generate the botif string, and the hardware-based config string
+ */
+static void make_bootif_string(void)
+{
+ char mac[18];
+ char *src = mac;
+ char *dst = MAC_str;
+ int i = MAC_len + 1;
+
+ *(uint8_t *)src++ = MAC_type;
+ memcpy(src, MAC, MAC_len);
+ src = mac;
+ for (; i > 0; i--) {
+ lchexbytes(dst, src, 1);
+ dst += 2;
+ src += 1;
+ *dst++ = '-';
+ }
+ *(dst - 1) = 0; /* Drop the last '-' and null-terminate string */
+ strcat(BOOTIFStr, "BOOTIF=");
+ strcat(BOOTIFStr, MAC_str);
+
+#if 0
+ printf("%s\n", BOOTIFStr);
+#endif
+}
+/*
+ * Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask>
+ * option into IPOption based on a DHCP packet in trackbuf.
+ *
+ */
+static void genipopt(void)
+{
+ char *p = IPOption;
+ int ip_len;
+
+ strcpy(p, "ip=");
+ p += 3;
+
+ ip_len = gendotquad(p, MyIP);
+ p += ip_len;
+ *p++ = ':';
+
+ ip_len = gendotquad(p, server_ip);
+ p += ip_len;
+ *p++ = ':';
+
+ ip_len = gendotquad(p, gate_way);
+ p += ip_len;
+ *p++ = ':';
+
+ ip_len = gendotquad(p, net_mask);
+}
+
+
+/* Generate ip= option and print the ip adress */
+static void ip_init(void)
+{
+ uint32_t ip = MyIP;
+
+ genipopt();
+ gendotquad(dot_quad_buf, ip);
+
+ ip = ntohl(ip);
+ printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf);
+ printf("%s\n", IPOption);
+}
+
+/*
+ * Validity check on possible !PXE structure in buf
+ * return 1 for success, 0 for failure.
+ *
+ */
+static int is_pxe(const void *buf)
+{
+ const struct pxe_t *pxe = buf;
+ const uint8_t *p = buf;
+ int i = pxe->structlength;
+ uint8_t sum = 0;
+
+ if (i < sizeof(struct pxe_t) ||
+ memcmp(pxe->signature, "!PXE", 4))
+ return 0;
+
+ while (i--)
+ sum += *p++;
+
+ return sum == 0;
+}
+
+/*
+ * Just like is_pxe, it checks PXENV+ structure
+ *
+ */
+static int is_pxenv(const void *buf)
+{
+ const struct pxenv_t *pxenv = buf;
+ const uint8_t *p = buf;
+ int i = pxenv->length;
+ uint8_t sum = 0;
+
+ /* The pxeptr field isn't present in old versions */
+ if (i < offsetof(struct pxenv_t, pxeptr) ||
+ memcmp(pxenv->signature, "PXENV+", 6))
+ return 0;
+
+ while (i--)
+ sum += *p++;
+
+ return sum == 0;
+}
+
+
+
+/*
+ * memory_scan_for_pxe_struct:
+ * memory_scan_for_pxenv_struct:
+ *
+ * If none of the standard methods find the !PXE/PXENV+ structure,
+ * look for it by scanning memory.
+ *
+ * return the corresponding pxe structure if found, or NULL;
+ */
+static const void *memory_scan(uintptr_t start, int (*func)(const void *))
+{
+ const char *ptr;
+
+ /* Scan each 16 bytes of conventional memory before the VGA region */
+ for (ptr = (const char *)start; ptr < (const char *)0xA0000; ptr += 16) {
+ if (func(ptr))
+ return ptr; /* found it! */
+ ptr += 16;
+ }
+ return NULL;
+}
+
+static const struct pxe_t *memory_scan_for_pxe_struct(void)
+{
+ extern uint16_t BIOS_fbm; /* Starting segment */
+
+ return memory_scan(BIOS_fbm << 10, is_pxe);
+}
+
+static const struct pxenv_t *memory_scan_for_pxenv_struct(void)
+{
+ return memory_scan(0x10000, is_pxenv);
+}
+
+/*
+ * Find the !PXE structure; we search for the following, in order:
+ *
+ * a. !PXE structure as SS:[SP + 4]
+ * b. PXENV+ structure at [ES:BX]
+ * c. INT 1Ah AX=0x5650 -> PXENV+
+ * d. Search memory for !PXE
+ * e. Search memory for PXENV+
+ *
+ * If we find a PXENV+ structure, we try to find a !PXE structure from
+ * if if the API version is 2.1 or later
+ *
+ */
+static int pxe_init(void)
+{
+ extern void pxe_int1a(void);
+ char plan = 'A';
+ uint16_t seg, off;
+ uint16_t code_seg, code_len;
+ uint16_t data_seg, data_len;
+ char *base = GET_PTR(InitStack);
+ com32sys_t regs;
+ const char *type;
+ const struct pxenv_t *pxenv;
+ const struct pxe_t *pxe;
+
+ /* Assume API version 2.1 */
+ APIVer = 0x201;
+
+ /* Plan A: !PXE structure as SS:[SP + 4] */
+ off = *(uint16_t *)(base + 48);
+ seg = *(uint16_t *)(base + 50);
+ pxe = MK_PTR(seg, off);
+ if (is_pxe(pxe))
+ goto have_pxe;
+
+ /* Plan B: PXENV+ structure at [ES:BX] */
+ plan++;
+ off = *(uint16_t *)(base + 24); /* Original BX */
+ seg = *(uint16_t *)(base + 4); /* Original ES */
+ pxenv = MK_PTR(seg, off);
+ if (is_pxenv(pxenv))
+ goto have_pxenv;
+
+ /* Plan C: PXENV+ structure via INT 1Ah AX=5650h */
+ plan++;
+ memset(&regs, 0, sizeof regs);
+ regs.eax.w[0] = 0x5650;
+ call16(pxe_int1a, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_CF) && (regs.eax.w[0] == 0x564e)) {
+ pxenv = MK_PTR(regs.es, regs.ebx.w[0]);
+ if (is_pxenv(pxenv))
+ goto have_pxenv;
+ }
+
+ /* Plan D: !PXE memory scan */
+ plan++;
+ if ((pxe = memory_scan_for_pxe_struct()))
+ goto have_pxe;
+
+ /* Plan E: PXENV+ memory scan */
+ plan++;
+ if ((pxenv = memory_scan_for_pxenv_struct()))
+ goto have_pxenv;
+
+ /* Found nothing at all !! */
+ printf("No !PXE or PXENV+ API found; we're dead...\n");
+ kaboom();
+
+ have_pxenv:
+ APIVer = pxenv->version;
+ printf("Found PXENV+ structure\nPXE API version is %04x\n", APIVer);
+
+ /* if the API version number is 0x0201 or higher, use the !PXE structure */
+ if (APIVer >= 0x201) {
+ if (pxenv->length >= sizeof(struct pxenv_t)) {
+ pxe = GET_PTR(pxenv->pxeptr);
+ if (is_pxe(pxe))
+ goto have_pxe;
+ /*
+ * Nope, !PXE structure missing despite API 2.1+, or at least
+ * the pointer is missing. Do a last-ditch attempt to find it
+ */
+ if ((pxe = memory_scan_for_pxe_struct()))
+ goto have_pxe;
+ }
+ }
+
+ /* Otherwise, no dice, use PXENV+ structure */
+ data_len = pxenv->undidatasize;
+ data_seg = pxenv->undidataseg;
+ code_len = pxenv->undicodesize;
+ code_seg = pxenv->undicodeseg;
+ PXEEntry = pxenv->rmentry;
+ type = "PXENV+";
+ goto have_entrypoint;
+
+ have_pxe:
+ data_len = pxe->seg[PXE_Seg_UNDIData].size;
+ data_seg = pxe->seg[PXE_Seg_UNDIData].sel;
+ code_len = pxe->seg[PXE_Seg_UNDICode].size;
+ code_seg = pxe->seg[PXE_Seg_UNDICode].sel;
+ PXEEntry = pxe->entrypointsp;
+ type = "!PXE";
+
+ have_entrypoint:
+ printf("%s entry point found (we hope) at %04X:%04X via plan %c\n",
+ type, PXEEntry.seg, PXEEntry.offs, plan);
+ printf("UNDI code segment at %04X len %04X\n", code_seg, code_len);
+ printf("UNDI data segment at %04X len %04X\n", data_seg, data_len);
+
+ code_seg = code_seg + ((code_len + 15) >> 4);
+ data_seg = data_seg + ((data_len + 15) >> 4);
+
+ real_base_mem = max(code_seg,data_seg) >> 6; /* Convert to kilobytes */
+
+ return 0;
+}
+
+/*
+ * Initialize UDP stack
+ *
+ */
+static void udp_init(void)
+{
+ int err;
+ static __lowmem struct s_PXENV_UDP_OPEN udp_open;
+ udp_open.src_ip = MyIP;
+ err = pxe_call(PXENV_UDP_OPEN, &udp_open);
+ if (err || udp_open.status) {
+ printf("Failed to initialize UDP stack ");
+ printf("%d\n", udp_open.status);
+ kaboom();
+ }
+}
+
+
+/*
+ * Network-specific initialization
+ */
+static void network_init(void)
+{
+ struct bootp_t *bp = (struct bootp_t *)trackbuf;
+ int pkt_len;
+
+ *LocalDomain = 0; /* No LocalDomain received */
+
+ /*
+ * Get the DHCP client identifiers (query info 1)
+ */
+ printf("Getting cached packet ");
+ pkt_len = pxe_get_cached_info(1);
+ parse_dhcp(pkt_len);
+ /*
+ * We don't use flags from the request packet, so
+ * this is a good time to initialize DHCPMagic...
+ * Initialize it to 1 meaning we will accept options found;
+ * in earlier versions of PXELINUX bit 0 was used to indicate
+ * we have found option 208 with the appropriate magic number;
+ * we no longer require that, but MAY want to re-introduce
+ * it in the future for vendor encapsulated options.
+ */
+ *(char *)&DHCPMagic = 1;
+
+ /*
+ * Get the BOOTP/DHCP packet that brought us file (and an IP
+ * address). This lives in the DHCPACK packet (query info 2)
+ */
+ pkt_len = pxe_get_cached_info(2);
+ parse_dhcp(pkt_len);
+ /*
+ * Save away MAC address (assume this is in query info 2. If this
+ * turns out to be problematic it might be better getting it from
+ * the query info 1 packet
+ */
+ MAC_len = bp->hardlen > 16 ? 0 : bp->hardlen;
+ MAC_type = bp->hardware;
+ memcpy(MAC, bp->macaddr, MAC_len);
+
+ /*
+ * Get the boot file and other info. This lives in the CACHED_REPLY
+ * packet (query info 3)
+ */
+ pkt_len = pxe_get_cached_info(3);
+ parse_dhcp(pkt_len);
+ printf("\n");
+
+ make_bootif_string();
+ ip_init();
+
+ /*
+ * Check to see if we got any PXELINUX-specific DHCP options; in particular,
+ * if we didn't get the magic enable, do not recognize any other options.
+ */
+ if ((DHCPMagic & 1) == 0)
+ DHCPMagic = 0;
+
+ udp_init();
+}
+
+/*
+ * Initialize pxe fs
+ *
+ */
+static int pxe_fs_init(struct fs_info *fs)
+{
+ (void)fs; /* drop the compile warning message */
+
+ /* Initialize the Files structure */
+ files_init();
+
+ /* do the pxe initialize */
+ pxe_init();
+
+ /* Network-specific initialization */
+ network_init();
+
+ /* Initialize network-card-specific idle handling */
+ pxe_idle_init();
+
+ return 0;
+}
+
+inline void reset_pxe(void)
+{
+ static __lowmem struct s_PXENV_UDP_CLOSE udp_close;
+ pxe_call(PXENV_UDP_CLOSE, &udp_close);
+}
+
+/*
+ * This function unloads the PXE and UNDI stacks and
+ * unclaims the memory.
+ */
+void unload_pxe(void)
+{
+ uint8_t api;
+ const uint8_t *api_ptr;
+ uint16_t flag = 0;
+ int err;
+ int int_addr;
+ static __lowmem struct s_PXENV_UNLOAD_STACK unload_stack;
+
+ pxe_idle_cleanup();
+
+ if (KeepPXE) {
+ /*
+ * We want to keep PXE around, but still we should reset
+ * it to the standard bootup configuration.
+ */
+ reset_pxe();
+ return;
+ }
+
+ api_ptr = major_ver(APIVer) >= 2 ? new_api_unload : old_api_unload;
+ while((api = *api_ptr++)) {
+ memset(&unload_stack, 0, sizeof unload_stack);
+ err = pxe_call(api, &unload_stack);
+ if (err || unload_stack.Status != PXENV_STATUS_SUCCESS)
+ goto cant_free;
+ }
+
+ flag = 0xff00;
+ if (real_base_mem <= BIOS_fbm) /* Santiy check */
+ goto cant_free;
+ flag ++;
+
+ /* Check that PXE actually unhooked the INT 0x1A chain */
+ int_addr = (int)MK_PTR(*(uint16_t *)(4*0x1a+2), *(uint16_t *)(4*0x1a));
+ int_addr >>= 10;
+ if (int_addr >= real_base_mem || int_addr < BIOS_fbm) {
+ BIOS_fbm = real_base_mem;
+ return;
+ }
+
+cant_free:
+ printf("Failed to free base memory error %04x-%08x\n",
+ flag, *(uint32_t *)(4 * 0x1a));
+ return;
+}
+
+
+
+const struct fs_ops pxe_fs_ops = {
+ .fs_name = "pxe",
+ .fs_flags = FS_NODEV,
+ .fs_init = pxe_fs_init,
+ .searchdir = pxe_searchdir,
+ .getfssec = pxe_getfssec,
+ .close_file = pxe_close_file,
+ .mangle_name = pxe_mangle_name,
+ .unmangle_name = pxe_unmangle_name,
+ .load_config = pxe_load_config,
+ .iget_current = NULL
+};
diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h
new file mode 100644
index 00000000..f62fa7a7
--- /dev/null
+++ b/core/fs/pxe/pxe.h
@@ -0,0 +1,224 @@
+/* -----------------------------------------------------------------------
+ *
+ * Copyright 1999-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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * pxe.h
+ *
+ * PXE opcodes
+ *
+ */
+#ifndef PXE_H
+#define PXE_H
+
+#include <syslinux/pxe_api.h>
+#include "fs.h" /* For MAX_OPEN, should go away */
+
+/*
+ * Some basic defines...
+ */
+#define TFTP_PORT htons(69) /* Default TFTP port */
+#define TFTP_BLOCKSIZE_LG2 9
+#define TFTP_BLOCKSIZE (1 << TFTP_BLOCKSIZE_LG2)
+#define PKTBUF_SEG 0x4000
+#define PKTBUF_SIZE (65536 / MAX_OPEN)
+
+#define is_digit(c) (((c) >= '0') && ((c) <= '9'))
+#define major_ver(v) (((v) >> 8) && 0xff)
+
+/*
+ * TFTP operation codes
+ */
+#define TFTP_RRQ htons(1) // Read rest
+#define TFTP_WRQ htons(2) // Write rest
+#define TFTP_DATA htons(3) // Data packet
+#define TFTP_ACK htons(4) // ACK packet
+#define TFTP_ERROR htons(5) // ERROR packet
+#define TFTP_OACK htons(6) // OACK packet
+
+/*
+ * TFTP error codes
+ */
+#define TFTP_EUNDEF htons(0) // Unspecified error
+#define TFTP_ENOTFOUND htons(1) // File not found
+#define TFTP_EACCESS htons(2) // Access violation
+#define TFTP_ENOSPACE htons(3) // Disk full
+#define TFTP_EBADOP htons(4) // Invalid TFTP operation
+#define TFTP_EBADID htons(5) // Unknown transfer
+#define TFTP_EEXISTS htons(6) // File exists
+#define TFTP_ENOUSER htons(7) // No such user
+#define TFTP_EOPTNEG htons(8) // Option negotiation failure
+
+
+#define BOOTP_OPTION_MAGIC htonl(0x63825363)
+#define MAC_MAX 32
+
+/* Defines for DNS */
+#define DNS_PORT htons(53) /* Default DNS port */
+#define DNS_MAX_PACKET 512 /* Defined by protocol */
+/* All local DNS queries come from this port */
+#define DNS_LOCAL_PORT htons(60053)
+#define DNS_MAX_SERVERS 4 /* Max no of DNS servers */
+
+
+/*
+ * structures
+ */
+
+struct pxenv_t {
+ uint8_t signature[6]; /* PXENV+ */
+ uint16_t version;
+ uint8_t length;
+ uint8_t checksum;
+ segoff16_t rmentry;
+ uint32_t pmoffset;
+ uint16_t pmselector;
+ uint16_t stackseg;
+ uint16_t stacksize;
+ uint16_t bc_codeseg;
+ uint16_t bc_codesize;
+ uint16_t bc_dataseg;
+ uint16_t bc_datasize;
+ uint16_t undidataseg;
+ uint16_t undidatasize;
+ uint16_t undicodeseg;
+ uint16_t undicodesize;
+ segoff16_t pxeptr;
+} __packed;
+
+struct pxe_t {
+ uint8_t signature[4]; /* !PXE */
+ uint8_t structlength;
+ uint8_t structcksum;
+ uint8_t structrev;
+ uint8_t _pad1;
+ segoff16_t undiromid;
+ segoff16_t baseromid;
+ segoff16_t entrypointsp;
+ segoff16_t entrypointesp;
+ segoff16_t statuscallout;
+ uint8_t _pad2;
+ uint8_t segdesccnt;
+ uint16_t firstselector;
+ pxe_segdesc_t seg[7];
+} __packed;
+
+enum pxe_segments {
+ PXE_Seg_Stack = 0,
+ PXE_Seg_UNDIData = 1,
+ PXE_Seg_UNDICode = 2,
+ PXE_Seg_UNDICodeWrite = 3,
+ PXE_Seg_BC_Data = 4,
+ PXE_Seg_BC_Code = 5,
+ PXE_Seg_BC_CodeWrite = 6
+};
+
+struct bootp_t {
+ uint8_t opcode; /* BOOTP/DHCP "opcode" */
+ uint8_t hardware; /* ARP hreadware type */
+ uint8_t hardlen; /* Hardware address length */
+ uint8_t gatehops; /* Used by forwarders */
+ uint32_t ident; /* Transaction ID */
+ uint16_t seconds; /* Seconds elapsed */
+ uint16_t flags; /* Broadcast flags */
+ uint32_t cip; /* Cient IP */
+ uint32_t yip; /* "Your" IP */
+ uint32_t sip; /* Next Server IP */
+ uint32_t gip; /* Relay agent IP */
+ uint8_t macaddr[16]; /* Client MAC address */
+ uint8_t sname[64]; /* Server name (optional) */
+ char bootfile[128]; /* Boot file name */
+ uint32_t option_magic; /* Vendor option magic cookie */
+ uint8_t options[1260]; /* Vendor options */
+} __attribute__ ((packed));
+
+struct open_file_t {
+ uint16_t tftp_localport; /* Local port number (0=not in us)*/
+ uint16_t tftp_remoteport; /* Remote port number */
+ uint32_t tftp_remoteip; /* Remote IP address */
+ uint32_t tftp_filepos; /* bytes downloaded (includeing buffer) */
+ uint32_t tftp_filesize; /* Total file size(*) */
+ uint32_t tftp_blksize; /* Block size for this connection(*) */
+ uint16_t tftp_bytesleft; /* Unclaimed data bytes */
+ uint16_t tftp_lastpkt; /* Sequence number of last packet (NBO) */
+ uint16_t tftp_dataptr; /* Pointer to available data */
+ uint8_t tftp_goteof; /* 1 if the EOF packet received */
+ uint8_t tftp_unused; /* Currently unused */
+ /* These values are preinitialized and not zeroed on close */
+ uint16_t tftp_nextport; /* Next port number for this slot (HBO) */
+ uint16_t tftp_pktbuf; /* Packet buffer offset */
+} __attribute__ ((packed));
+
+/*
+ * Variable externs
+ */
+extern uint32_t server_ip;
+extern uint32_t MyIP;
+extern uint32_t net_mask;
+extern uint32_t gate_way;
+extern uint16_t server_port;
+
+extern char MAC_str[];
+extern char MAC[];
+extern char BOOTIFStr[];
+extern uint8_t MAC_len;
+extern uint8_t MAC_type;
+
+extern uint8_t DHCPMagic;
+extern uint32_t RebootTime;
+
+extern char boot_file[];
+extern char path_prefix[];
+extern char LocalDomain[];
+
+extern char packet_buf[];
+
+extern char IPOption[];
+extern char dot_quad_buf[];
+
+extern uint32_t dns_server[];
+
+extern uint16_t real_base_mem;
+extern uint16_t APIVer;
+extern far_ptr_t PXEEntry;
+extern uint8_t KeepPXE;
+
+extern far_ptr_t InitStack;
+
+extern int have_uuid;
+extern uint8_t uuid_type;
+extern char uuid[];
+
+extern uint16_t BIOS_fbm;
+extern const uint8_t TimeoutTable[];
+
+
+/*
+ * functions
+ */
+
+/* pxe.c */
+int ip_ok(uint32_t);
+int pxe_call(int, void *);
+
+/* dhcp_options.c */
+void parse_dhcp(int);
+void parse_dhcp_options(void *, int, int);
+
+/* dnsresolv.c */
+int dns_mangle(char **, const char *);
+uint32_t dns_resolv(const char *);
+
+/* idle.c */
+void pxe_idle_init(void);
+void pxe_idle_cleanup(void);
+
+#endif /* pxe.h */
diff --git a/core/getc.inc b/core/getc.inc
index bb12047b..48b9f774 100644
--- a/core/getc.inc
+++ b/core/getc.inc
@@ -60,8 +60,9 @@ getc_file_lg2 equ 4 ; Size of getc_file as a power of 2
;
; close: Output: CF set if nothing open
;
-open:
- call searchdir
+ global core_open
+core_open:
+ pm_call searchdir
jz openfd.ret
openfd:
push bx
@@ -82,11 +83,11 @@ openfd:
.ret: ret
.stack_full:
- call close_file
+ pm_call close_file
xor ax,ax ; ZF <- 1
pop bx
ret
-
+
getc:
push bx
push si
@@ -135,7 +136,7 @@ getc:
mov [di+gc_bufbytes],si ; In case SI == 0
jz .empty
mov cx,bytes_per_getc >> SECTOR_SHIFT
- call getfssec
+ pm_call getfssec
mov [di+gc_bufbytes],cx
mov [di+gc_file],si
jcxz .empty
@@ -177,7 +178,7 @@ close:
push si
mov bx,[CurrentGetC]
mov si,[bx+gc_file]
- call close_file
+ pm_call close_file
add bx,getc_file_size
mov [CurrentGetC],bx
pop si
@@ -321,7 +322,7 @@ parseint:
.isk: shl ebx,10 ; * 2^10
jmp .fini
- section .bss1
+ section .bss16
alignb 4
NumBuf resb 15 ; Buffer to load number
NumBufEnd resb 1 ; Last byte in NumBuf
@@ -329,14 +330,14 @@ NumBufEnd resb 1 ; Last byte in NumBuf
GetCStack resb getc_file_size*MAX_GETC
.end equ $
- section .data
+ section .data16
CurrentGetC dw GetCStack.end ; GetCStack empty
;
; unhexchar: Convert a hexadecimal digit in AL to the equivalent number;
; return CF=1 if not a hex digit
;
- section .text
+ section .text16
unhexchar:
cmp al,'0'
jb .ret ; If failure, CF == 1 already
diff --git a/core/graphics.inc b/core/graphics.inc
index 26925e9a..a8d28515 100644
--- a/core/graphics.inc
+++ b/core/graphics.inc
@@ -21,7 +21,7 @@
;
; Assumes CS == DS == ES.
;
- section .text
+ section .text16
vgadisplayfile:
; This is a cheap and easy way to make sure the screen is
@@ -322,7 +322,7 @@ vgacursorcommon:
ret
- section .data
+ section .data16
; Map colors to consecutive DAC registers
linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
@@ -330,7 +330,7 @@ linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0
; of this byte.
UsingVGA db 0
- section .bss2
+ section .bss16
alignb 4
LSSHeader equ $
LSSMagic resd 1 ; Magic number
diff --git a/core/head.inc b/core/head.inc
index 7117b4ee..18ce132c 100644
--- a/core/head.inc
+++ b/core/head.inc
@@ -20,9 +20,15 @@
%ifndef _HEAD_INC
%define _HEAD_INC
+%if __NASM_MAJOR__ < 2
+ %error "NASM 2.00 or later required to compile correctly"
+%endif
+
%include "macros.inc"
%include "config.inc"
%include "layout.inc"
+%include "pmcall.inc"
+%include "extern.inc"
%include "kernel.inc"
%include "bios.inc"
%include "tracers.inc"
diff --git a/core/hello.c b/core/hello.c
new file mode 100644
index 00000000..a1591111
--- /dev/null
+++ b/core/hello.c
@@ -0,0 +1,30 @@
+#include <stddef.h>
+#include <com32.h>
+#include <stdio.h>
+#include <string.h>
+
+
+void myputchar(int c)
+{
+ static com32sys_t ireg;
+
+ if (c == '\n')
+ myputchar('\r');
+
+ ireg.eax.b[1] = 0x02;
+ ireg.edx.b[0] = c;
+ __intcall(0x21, &ireg, NULL);
+}
+
+void myputs(const char *str)
+{
+ while (*str)
+ myputchar(*str++);
+}
+
+void hello(void)
+{
+ static char hello_str[] = "Hello, World!";
+
+ printf("%s from (%s)\n", hello_str, __FILE__); /* testing */
+}
diff --git a/core/highmem.inc b/core/highmem.inc
index 1f8349bd..ea386ffc 100644
--- a/core/highmem.inc
+++ b/core/highmem.inc
@@ -17,7 +17,7 @@
;; mem= command on the command line while booting a new kernel.
;;
- section .text
+ section .text16
;
; This is set up as a subroutine; it will set up the global variable
@@ -150,9 +150,9 @@ got_highmem:
pop es
ret ; Done!
- section .bss
+ section .bss16
alignb 4
E820Buf resd 5 ; INT 15:E820 data buffer
E820Mem resd 1 ; Memory detected by E820
E820Max resd 1 ; Is E820 memory capped?
-HighMemSize resd 1 ; End of memory pointer (bytes)
+; HighMemSize is defined in com32.inc
diff --git a/core/idle.inc b/core/idle.inc
index bd134ff6..8d699733 100644
--- a/core/idle.inc
+++ b/core/idle.inc
@@ -11,19 +11,19 @@
;;
;; -----------------------------------------------------------------------
- section .text
+ section .text16
TICKS_TO_IDLE equ 4
reset_idle:
- push ax
- mov ax,[cs:BIOS_timer]
- mov [cs:IdleTimer],ax
- pop ax
+ push eax
+ mov eax,[cs:__jiffies]
+ mov [cs:IdleTimer],eax
+ pop eax
sti ; Guard against BIOS/PXE brokenness...
ret
do_idle:
- push ax
+ push eax
push ds
push es
mov ax,cs
@@ -54,25 +54,33 @@ do_idle:
pop si
sti
.ok:
- mov ax,[BIOS_timer]
- sub ax,[IdleTimer]
- cmp ax,TICKS_TO_IDLE
+ mov eax,[__jiffies]
+ sub eax,[IdleTimer]
+ cmp eax,TICKS_TO_IDLE
jb .done
- call [IdleHook]
+
+ mov eax,[idle_hook_func]
+ and eax,eax
+ jz .no_idle_hook
+ pm_call eax
+.no_idle_hook:
cmp word [NoHalt],0
jne .done
hlt
.done:
pop es
pop ds
- pop ax
+ pop eax
.ret: ret
- section .data
-IdleHook dw do_idle.ret
+ section .data16
+ alignz 4
+ global idle_hook_func
+idle_hook_func dd 0
NoHalt dw 0
hlt_err db 'ERROR: idle with IF=0', CR, LF, 0
- section .bss
-IdleTimer resw 1
+ section .bss16
+ alignb 4
+IdleTimer resd 1
diff --git a/core/include/cache.h b/core/include/cache.h
new file mode 100644
index 00000000..7518bc84
--- /dev/null
+++ b/core/include/cache.h
@@ -0,0 +1,25 @@
+#ifndef _CACHE_H
+#define _CACHE_H
+
+#include <stdint.h>
+#include <com32.h>
+#include "disk.h"
+#include "fs.h"
+
+#define MAX_CACHE_ENTRIES 0x10 /* I find even this is enough:) */
+
+/* The cache structure */
+struct cache_struct {
+ block_t block;
+ struct cache_struct *prev;
+ struct cache_struct *next;
+ void *data;
+};
+
+
+/* functions defined in cache.c */
+void cache_init(struct device *, int);
+struct cache_struct* get_cache_block(struct device *, block_t);
+void print_cache(struct device *);
+
+#endif /* cache.h */
diff --git a/core/include/core.h b/core/include/core.h
new file mode 100644
index 00000000..1a9e1b96
--- /dev/null
+++ b/core/include/core.h
@@ -0,0 +1,60 @@
+#ifndef CORE_H
+#define CORE_H
+
+#include <klibc/compiler.h>
+#include <com32.h>
+
+extern char core_xfer_buf[65536];
+extern char core_cache_buf[65536];
+extern char trackbuf[];
+extern char CurrentDirName[];
+extern char ConfigName[];
+extern char KernelName[];
+
+/* diskstart.inc isolinux.asm*/
+extern void getlinsec(void);
+
+/* getc.inc */
+extern void core_open(void);
+
+/* idle.inc */
+extern void (*idle_hook_func)(void);
+
+/* hello.c */
+extern void myputs(const char*);
+
+/* malloc.c */
+extern void *malloc(int);
+extern void free(void *);
+extern void mem_init(void);
+
+void __cdecl core_intcall(uint8_t, const com32sys_t *, com32sys_t *);
+void __cdecl core_farcall(uint32_t, const com32sys_t *, com32sys_t *);
+int __cdecl core_cfarcall(uint32_t, const void *, uint32_t);
+
+extern const com32sys_t zero_regs;
+void call16(void (*)(void), const com32sys_t *, com32sys_t *);
+
+/*
+ * __lowmem is in the low 1 MB; __bss16 in the low 64K
+ */
+#define __lowmem __attribute((nocommon,section(".lowmem")))
+#define __bss16 __attribute((nocommon,section(".bss16")))
+
+/*
+ * Death! The macro trick is to avoid symbol conflict with
+ * the real-mode symbol kaboom.
+ */
+__noreturn _kaboom(void);
+#define kaboom() _kaboom()
+
+/*
+ * Basic timer function...
+ */
+extern const volatile uint32_t __jiffies;
+static inline uint32_t jiffies(void)
+{
+ return __jiffies;
+}
+
+#endif /* CORE_H */
diff --git a/core/include/disk.h b/core/include/disk.h
new file mode 100644
index 00000000..55d24fbc
--- /dev/null
+++ b/core/include/disk.h
@@ -0,0 +1,39 @@
+#ifndef DISK_H
+#define DISK_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define SECTOR_SHIFT 9
+
+typedef uint64_t sector_t;
+typedef uint64_t block_t;
+
+
+/*
+ * struct disk: contains the information about a specific disk and also
+ * contains the I/O function.
+ */
+struct disk {
+ uint8_t disk_number; /* in BIOS style */
+ uint8_t type; /* CHS or EDD */
+ uint16_t sector_size; /* gener512B or 2048B */
+ uint8_t sector_shift;
+
+ uint8_t h, s; /* CHS geometry */
+ uint8_t pad;
+
+ sector_t part_start; /* the start address of this partition(in sectors) */
+
+ int (*rdwr_sectors)(struct disk *, void *, sector_t, size_t, bool);
+};
+
+extern void read_sectors(char *, sector_t, int);
+extern void getoneblk(struct disk *, char *, block_t, int);
+
+/* diskio.c */
+struct disk *disk_init(uint8_t, bool, sector_t, uint16_t, uint16_t);
+struct device *device_init(uint8_t, bool, sector_t, uint16_t, uint16_t);
+
+#endif /* DISK_H */
diff --git a/core/include/fs.h b/core/include/fs.h
new file mode 100644
index 00000000..f0fe5347
--- /dev/null
+++ b/core/include/fs.h
@@ -0,0 +1,169 @@
+#ifndef FS_H
+#define FS_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <string.h>
+#include <com32.h>
+#include <stdio.h>
+#include "core.h"
+#include "disk.h"
+
+/*
+ * Maximum number of open files. This is *currently* constrained by the
+ * fact that PXE needs to be able to fit all its packet buffers into a
+ * 64K segment; this should be fixed by moving the packet buffers to high
+ * memory.
+ */
+#define MAX_OPEN_LG2 5
+#define MAX_OPEN (1 << MAX_OPEN_LG2)
+
+#define FILENAME_MAX_LG2 8
+#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+
+#define BLOCK_SIZE(fs) (1 << fs->block_shift)
+#define SECTOR_SIZE(fs) (1 << fs->sector_shift)
+
+struct fs_info {
+ const struct fs_ops *fs_ops;
+ struct device *fs_dev;
+ void *fs_info; /* The fs-specific information */
+ int sector_shift;
+ int block_shift;
+};
+
+extern struct fs_info *this_fs;
+
+struct dirent; /* Directory entry structure */
+struct file;
+enum fs_flags {
+ FS_NODEV = 1 << 0,
+ FS_USEMEM = 1 << 1, /* If we need a malloc routine, set it */
+
+ /*
+ * Update the this_inode pointer at each part of path searching. This
+ * flag is just used for FAT and ISO fs for now.
+ */
+ FS_THISIND = 1 << 2,
+};
+
+struct fs_ops {
+ /* in fact, we use fs_ops structure to find the right fs */
+ const char *fs_name;
+ enum fs_flags fs_flags;
+
+ int (*fs_init)(struct fs_info *);
+ void (*searchdir)(char *, struct file *);
+ uint32_t (*getfssec)(struct file *, char *, int, bool *);
+ void (*close_file)(struct file *);
+ void (*mangle_name)(char *, const char *);
+ char * (*unmangle_name)(char *, const char *);
+ int (*load_config)();
+
+ struct inode * (*iget_root)(void);
+ struct inode * (*iget_current)(void);
+ struct inode * (*iget)(char *, struct inode *);
+ char * (*follow_symlink)(struct inode *, const char *);
+
+ /* the _dir_ stuff */
+ struct dirent * (*readdir)(struct file *);
+};
+
+enum inode_mode {I_FILE, I_DIR, I_SYMLINK};
+
+/*
+ * The inode structure, including the detail file information
+ */
+struct inode {
+ int mode; /* FILE , DIR or SYMLINK */
+ uint32_t size;
+ uint32_t ino; /* Inode number */
+ uint32_t atime; /* Access time */
+ uint32_t mtime; /* Modify time */
+ uint32_t ctime; /* Create time */
+ uint32_t dtime; /* Delete time */
+ int blocks; /* How many blocks the file take */
+ uint32_t * data; /* The block address array where the file stored */
+ uint32_t flags;
+ uint32_t file_acl;
+};
+
+extern struct inode *this_inode;
+
+struct open_file_t;
+
+struct file {
+ struct fs_info *fs;
+ union {
+ /* For the new universal-path_lookup */
+ struct {
+ struct inode *inode; /* The file-specific information */
+ uint32_t offset; /* for next read */
+ };
+
+ /* For the old searhdir method */
+ struct {
+ struct open_file_t *open_file;/* The fs-specific open file struct */
+ uint32_t file_len;
+ };
+ };
+};
+
+
+enum dev_type {CHS, EDD};
+
+/*
+ * Generic functions that filesystem drivers may choose to use
+ */
+void generic_mangle_name(char *, const char *);
+#define generic_unmangle_name stpcpy
+
+/*
+ * Struct device contains:
+ * the pointer points to the disk structure,
+ * the cache stuff.
+ */
+struct device {
+ struct disk *disk;
+
+ /* the cache stuff */
+ char* cache_data;
+ void* cache_head;
+ uint16_t cache_block_size;
+ uint16_t cache_entries;
+ uint32_t cache_size;
+};
+
+/*
+ * Our definition of "not whitespace"
+ */
+static inline bool not_whitespace(char c)
+{
+ return (unsigned char)c > ' ';
+}
+
+static inline void free_inode(struct inode * inode)
+{
+ if (inode) {
+ if (inode->data)
+ free(inode->data);
+ free(inode);
+ }
+}
+
+static inline void malloc_error(char *obj)
+{
+ printf("Out of memory: can't allocate memory for %s\n", obj);
+ kaboom();
+}
+
+/*
+ * functions
+ */
+void mangle_name(com32sys_t *);
+void searchdir(com32sys_t *);
+void _close_file(struct file *);
+inline uint16_t file_to_handle(struct file *);
+inline struct file *handle_to_file(uint16_t);
+
+#endif /* FS_H */
diff --git a/core/init.inc b/core/init.inc
index 0b213ace..a3fe3041 100644
--- a/core/init.inc
+++ b/core/init.inc
@@ -2,6 +2,7 @@
; -----------------------------------------------------------------------
;
; Copyright 2004-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
@@ -17,10 +18,20 @@
; Common initialization code (inline)
;
- section .text
+ section .text16
common_init:
- ; Now set up screen parameters
- call adjust_screen
+ ; Initialize PM invocation framework
+ call pm_init
+
+ ; Decompress PM code to its target location
+ pm_call pm_decompress
+ cmp eax,__pm_code_len
+ jne kaboom
+
+;
+; Initialize timer
+;
+ call timer_init
;
; Initialize configuration information
@@ -28,20 +39,87 @@ common_init:
call reset_config
;
-; Clear Files structures
+; Set up the COMBOOT APIs
+;
+ call comboot_setup_api
+
+;
+; Now set up screen parameters
+;
+ call adjust_screen
+
+;
+; CPU-dependent initialization and related checks.
+;
+check_escapes:
+ mov ah,02h ; Check keyboard flags
+ int 16h
+ mov [KbdFlags],al ; Save for boot prompt check
+ test al,04h ; Ctrl->skip 386 check
+ jnz skip_checks
+
+;
+; Now check that there is sufficient low (DOS) memory
+;
+; NOTE: Linux doesn't use all of real_mode_seg, but we use the same
+; segment for COMBOOT images, which can use all 64K
+;
+dosram_k equ (real_mode_seg+0x1000) >> 6 ; Minimum DOS memory (K)
+ int 12h
+ cmp ax,dosram_k
+ jae enough_ram
+ mov si,err_noram
+ call writestr_early
+ jmp kaboom
+enough_ram:
+skip_checks:
+
+ section .data16
+err_noram db 'It appears your computer has less than '
+ asciidec dosram_k
+ db 'K of low ("DOS")'
+ db CR, LF
+ db 'RAM. Syslinux needs at least this amount to boot. If you get'
+ db CR, LF
+ db 'this message in error, hold down the Ctrl key while'
+ db CR, LF
+ db 'booting, and I will take your word for it.', CR, LF, 0
+ section .text16
+
+;
+; The code to decompress the PM code and initialize other segments.
;
- mov di,Files
- mov cx,(MAX_OPEN*open_file_t_size)/4
+ extern _lzo1x_decompress_asm_fast
+
+ section .textnr
+ bits 32
+pm_decompress:
+ push 0 ; Space for decompressed size
+ push esp ; Pointer to previous word
+ push __pm_code_start ; Target address
+ push dword [lzo_data_size] ; Compressed size
+ push dword __pm_code_lma
+ call _lzo1x_decompress_asm_fast
+ add esp,16
+ pop RM_EAX ; Decompressed size
+
+ ; Zero bss sections (but not .earlybss, since it may
+ ; contain already-live data.)
xor eax,eax
+ mov edi,__bss_start
+ mov ecx,__bss_dwords
+ rep stosd
+ mov edi,__bss16_start
+ mov ecx,__bss16_dwords
rep stosd
+ mov edi,__high_clear_start ; .uibss, .auxseg, .lowmem
+ mov ecx,__high_clear_dwords
+ rep stosd
+
+ ret
+
+ section .data16
+lzo_data_size dd 0 ; filled in by compressor
-%if IS_PXELINUX
- mov di,Files+tftp_pktbuf
- mov cx,MAX_OPEN
-.setbufptr:
- mov [di],ax
- add di,open_file_t_size
- add ax,PKTBUF_SIZE
- loop .setbufptr
-%endif
- section .text ; This is an inline file...
+ section .text16
+ bits 16
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 2627c2df..fef3e560 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -26,14 +26,10 @@
; Some semi-configurable constants... change on your own risk.
;
my_id equ isolinux_id
-FILENAME_MAX_LG2 equ 8 ; log2(Max filename size Including final null)
-FILENAME_MAX equ (1 << FILENAME_MAX_LG2)
NULLFILE equ 0 ; Zero byte == null file name
NULLOFFSET equ 0 ; Position in which to look
retry_count equ 6 ; How patient are we with the BIOS?
%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
-MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
-MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
@@ -72,12 +68,6 @@ file_left resd 1 ; Number of sectors left
%endif
%endif
- struc dir_t
-dir_lba resd 1 ; Directory start (LBA)
-dir_len resd 1 ; Length in bytes
-dir_clust resd 1 ; Length in clusters
- endstruc
-
; ---------------------------------------------------------------------------
; BEGIN CODE
; ---------------------------------------------------------------------------
@@ -86,18 +76,15 @@ dir_clust resd 1 ; Length in clusters
; Memory below this point is reserved for the BIOS and the MBR
;
section .earlybss
+ global trackbuf
trackbufsize equ 8192
trackbuf resb trackbufsize ; Track buffer goes here
; ends at 2800h
; Some of these are touched before the whole image
- ; is loaded. DO NOT move this to .uibss.
- section .bss2
+ ; is loaded. DO NOT move this to .bss16/.uibss.
+ section .earlybss
alignb 4
-ISOFileName resb 64 ; ISO filename canonicalization buffer
-ISOFileNameEnd equ $
-CurrentDir resb dir_t_size ; Current directory
-RootDir resb dir_t_size ; Root directory
FirstSecSum resd 1 ; Checksum of bytes 64-2048
ImageDwords resd 1 ; isolinux.bin size, dwords
InitStack resd 1 ; Initial stack pointer (SS:SP)
@@ -190,10 +177,7 @@ dsp_dummy: resb 1 ; Scratch, safe to overwrite
_spec_end equ $
_spec_len equ _spec_end - _spec_start
- alignb open_file_t_size
-Files resb MAX_OPEN*open_file_t_size
-
- section .text
+ section .init
;;
;; Primary entry point. Because BIOSes are buggy, we only load the first
;; CD-ROM sector (2K) of the file, so the number one priority is actually
@@ -203,6 +187,7 @@ StackBuf equ $-44 ; 44 bytes needed for
; the bootsector chainloading
; code!
OrigESDI equ StackBuf-4 ; The high dword on the stack
+StackTop equ OrigESDI
bootsec equ $
@@ -410,8 +395,8 @@ found_file:
sub eax,SECTOR_SIZE-3 ; ... minus sector loaded
shr eax,2 ; bytes->dwords
mov [ImageDwords],eax ; boot file dwords
- add eax,(2047 >> 2)
- shr eax,9 ; dwords->sectors
+ add eax,((SECTOR_SIZE-1) >> 2)
+ shr eax,SECTOR_SHIFT-2 ; dwords->sectors
mov [ImageSectors],ax ; boot file sectors
mov eax,[bi_file] ; Address of code to load
@@ -423,34 +408,54 @@ found_file:
call crlf
%endif
- ; Just in case some BIOSes have problems with
- ; segment wraparound, use the normalized address
- mov bx,((7C00h+2048) >> 4)
- mov es,bx
- xor bx,bx
+ ; Load the rest of the file. However, just in case there
+ ; are still BIOSes with 64K wraparound problems, we have to
+ ; take some extra precautions. Since the normal load
+ ; address (7C00h) is *not* 2K-sector-aligned, the safest
+ ; way to deal with this is to load into the xfer_buf_seg
+ ; and then copy the data in place.
+MaxLMA equ xfer_buf_seg << 4
+
+ mov bx,(7C00h+SECTOR_SIZE) >> 4
mov bp,[ImageSectors]
-%ifdef DEBUG_MESSAGES
- push ax
- mov si,size_msg
- call writemsg
- mov ax,bp
- call writehex4
- call crlf
- pop ax
-%endif
+
+.more:
+ push bx
+ push bp
+ mov dx,xfer_buf_seg
+ mov es,dx
+ mov fs,dx
+ xor bx,bx
+
+ cmp bp,0x10000 >> SECTOR_SHIFT
+ jbe .ok
+ mov bp,0x10000 >> SECTOR_SHIFT
+.ok:
+ push bp
call getlinsec
+ pop dx
+ pop bp
+ pop bx
+
+ mov es,bx
+ xor si,si
+ xor di,di
+ mov cx,dx
+ shl cx,SECTOR_SHIFT-2
+ fs rep movsd
+
+ mov cx,dx
+ shl cx,SECTOR_SHIFT-4
+ add bx,cx
+ sub bp,dx
+ jnz .more
push ds
pop es
-%ifdef DEBUG_MESSAGES
- mov si,loaded_msg
- call writemsg
-%endif
-
; Verify the checksum on the loaded image.
verify_image:
- mov si,7C00h+2048
+ mov si,7C00h+SECTOR_SIZE
mov bx,es
mov ecx,[ImageDwords]
mov edi,[FirstSecSum] ; First sector checksum
@@ -697,9 +702,7 @@ writemsg: push ax
;
writechr:
- jmp near writechr_simple ; 3-byte jump
-
-writechr_simple:
+.simple:
pushfd
pushad
mov ah,0Eh
@@ -747,6 +750,7 @@ getonesec:
; ES:BX - Target buffer
; BP - Sector count
;
+ global getlinsec
getlinsec: jmp word [cs:GetlinsecPtr]
%ifndef DEBUG_MESSAGES
@@ -1012,6 +1016,7 @@ xint13: mov byte [RetryCount],retry_count
; kaboom: write a message and bail out. Wait for a user keypress,
; then do a hard reboot.
;
+ global kaboom
disk_error:
kaboom:
RESET_STACK_AND_SEGS AX
@@ -1044,8 +1049,6 @@ startup_msg: db 'Starting up, DL = ', 0
spec_ok_msg: db 'Loaded spec packet OK, drive = ', 0
secsize_msg: db 'Sector size ', 0
offset_msg: db 'Main image LBA = ', 0
-size_msg: db 'Sectors to load = ', 0
-loaded_msg: db 'Loaded boot image, verifying...', CR, LF, 0
verify_msg: db 'Image checksum verified.', CR, LF, 0
allread_msg db 'Main image read, jumping to main code...', CR, LF, 0
%endif
@@ -1081,6 +1084,7 @@ bios_ebios: dw getlinsec_ebios, bios_ebios_str
%endif
; Maximum transfer size
+ global MaxTransfer
MaxTransfer dw 127 ; Hard disk modes
MaxTransferCD dw 32 ; CD mode
@@ -1094,6 +1098,8 @@ rl_checkpt equ $ ; Must be <= 800h
; End of code and data that have to be in the first sector
; ----------------------------------------------------------------------------
+ section .text16
+
all_read:
; Test tracers
@@ -1104,10 +1110,14 @@ all_read:
; Common initialization code
;
%include "init.inc"
-%include "cpuinit.inc"
; Patch the writechr routine to point to the full code
- mov word [writechr+1], writechr_full-(writechr+3)
+ mov di,writechr
+ mov al,0e9h
+ stosb
+ mov ax,writechr_full-2
+ sub ax,di
+ stosw
; Tell the user we got this far...
%ifndef DEBUG_MESSAGES ; Gets messy with debugging on
@@ -1135,95 +1145,31 @@ all_read:
; (which will be at 16 only for a single-session disk!); from the PVD
; we should be able to find the rest of what we need to know.
;
-get_fs_structures:
- mov eax,[bi_pvd]
- mov bx,trackbuf
- call getonesec
+ pushad
+ mov eax,ROOT_FS_OPS
+ mov dl,[DriveNumber]
+ cmp word [BIOSType],bios_cdrom
+ sete dh ; 1 for cdrom, 0 for hybrid mode
+ mov ecx,[bsHidden]
+ mov ebx,[bsHidden+4]
+ mov si,[bsHeads]
+ mov di,[bsSecPerTrack]
+ pm_call fs_init
+ popad
- mov eax,[trackbuf+156+2]
- mov [RootDir+dir_lba],eax
- mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
- mov si,dbg_rootdir_msg
- call writemsg
- call writehex8
- call crlf
-%endif
- mov eax,[trackbuf+156+10]
- mov [RootDir+dir_len],eax
- mov [CurrentDir+dir_len],eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [RootDir+dir_clust],eax
- mov [CurrentDir+dir_clust],eax
-
- ; Look for an isolinux directory, and if found,
- ; make it the current directory instead of the root
- ; directory.
- ; Also copy the name of the directory to CurrentDirName
- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
- mov di,boot_dir ; Search for /boot/isolinux
- mov al,02h
- push di
- call searchdir_iso
- pop di
- jnz .found_dir
- mov di,isolinux_dir
- mov al,02h ; Search for /isolinux
- push di
- call searchdir_iso
- pop di
- jz .no_isolinux_dir
-.found_dir:
- ; Copy current directory name to CurrentDirName
- push si
- push di
- mov si,di
- mov di,CurrentDirName
- call strcpy
- mov byte [di],0 ;done in case it's not word aligned
- dec di
- mov byte [di],'/'
- pop di
- pop si
+ section .rodata
+ alignz 4
+ROOT_FS_OPS:
+ extern iso_fs_ops
+ dd iso_fs_ops
+ dd 0
- mov [CurrentDir+dir_len],eax
- mov eax,[si+file_left]
- mov [CurrentDir+dir_clust],eax
- xor eax,eax ; Free this file pointer entry
- xchg eax,[si+file_sector]
- mov [CurrentDir+dir_lba],eax
-%ifdef DEBUG_MESSAGES
- push si
- mov si,dbg_isodir_msg
- call writemsg
- pop si
- call writehex8
- call crlf
-%endif
-.no_isolinux_dir:
+ section .text16
;
; Locate the configuration file
;
-load_config:
-%ifdef DEBUG_MESSAGES
- mov si,dbg_config_msg
- call writemsg
-%endif
-
- mov si,config_name
- mov di,ConfigName
- call strcpy
-
- mov di,ConfigName
- call open
- jz no_config_file ; Not found or empty
-
-%ifdef DEBUG_MESSAGES
- mov si,dbg_configok_msg
- call writemsg
-%endif
+ pm_call load_config
;
; Now we have the config file open. Parse the config file and
@@ -1264,7 +1210,7 @@ is_disk_image:
mov bx,trackbuf
mov cx,1 ; Load 1 sector
- call getfssec
+ pm_call getfssec
cmp word [trackbuf+510],0aa55h ; Boot signature
jne .bad_image ; Image not bootable
@@ -1361,391 +1307,23 @@ is_disk_image:
mov al,bl
.done_sector: ret
-;
-; close_file:
-; Deallocates a file structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_file:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_left
- xor si,si
-.closed: ret
-
-;
-; searchdir:
-;
-; Open a file
-;
-; On entry:
-; DS:DI = filename
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES, and trashes BX and CX.
-;
-; searchdir_iso is a special entry point for ISOLINUX only. In addition
-; to the above, searchdir_iso passes a file flag mask in AL. This is useful
-; for searching for directories.
-;
-alloc_failure:
- xor ax,ax ; ZF <- 1
- ret
-
-searchdir:
- xor al,al
-searchdir_iso:
- mov [ISOFlags],al
- TRACER 'S'
- call allocate_file ; Temporary file structure for directory
- jnz alloc_failure
- push es
- push ds
- pop es ; ES = DS
- mov si,CurrentDir
- cmp byte [di],'/' ; If filename begins with slash
- jne .not_rooted
- inc di ; Skip leading slash
- mov si,RootDir ; Reference root directory instead
-.not_rooted:
- mov eax,[si+dir_clust]
- mov [bx+file_left],eax
- shl eax,SECTOR_SHIFT
- mov [bx+file_bytesleft],eax
- mov eax,[si+dir_lba]
- mov [bx+file_sector],eax
- mov edx,[si+dir_len]
-
-.look_for_slash:
- mov ax,di
-.scan:
- mov cl,[di]
- inc di
- and cl,cl
- jz .isfile
- cmp cl,'/'
- jne .scan
- mov [di-1],byte 0 ; Terminate at directory name
- mov cl,02h ; Search for directory
- xchg cl,[ISOFlags]
-
- push di ; Save these...
- push cx
-
- ; Create recursion stack frame...
- push word .resume ; Where to "return" to
- push es
-.isfile: xchg ax,di
-
-.getsome:
- ; Get a chunk of the directory
- ; This relies on the fact that ISOLINUX doesn't change SI
- mov si,trackbuf
- TRACER 'g'
- pushad
- xchg bx,si
- mov cx,[BufSafe]
- call getfssec
- popad
-
-.compare:
- movzx eax,byte [si] ; Length of directory entry
- cmp al,33
- jb .next_sector
- TRACER 'c'
- mov cl,[si+25]
- xor cl,[ISOFlags]
- test cl, byte 8Eh ; Unwanted file attributes!
- jnz .not_file
- pusha
- movzx cx,byte [si+32] ; File identifier length
- add si,byte 33 ; File identifier offset
- TRACER 'i'
- call iso_compare_names
- popa
- je .success
-.not_file:
- sub edx,eax ; Decrease bytes left
- jbe .failure
- add si,ax ; Advance pointer
-
-.check_overrun:
- ; Did we finish the buffer?
- cmp si,trackbuf+trackbufsize
- jb .compare ; No, keep going
-
- jmp short .getsome ; Get some more directory
-
-.next_sector:
- ; Advance to the beginning of next sector
- lea ax,[si+SECTOR_SIZE-1]
- and ax,~(SECTOR_SIZE-1)
- sub ax,si
- jmp short .not_file ; We still need to do length checks
-
-.failure: xor eax,eax ; ZF = 1
- mov [bx+file_sector],eax
- pop es
- ret
-
-.success:
- 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
- jz .failure ; Empty file?
- ; ZF = 0
- mov si,bx
- pop es
- ret
-
-.resume: ; We get here if we were only doing part of a lookup
- ; This relies on the fact that .success returns bx == si
- xchg edx,eax ; Directory length in edx
- pop cx ; Old ISOFlags
- pop di ; Next filename pointer
- mov byte [di-1], '/' ; Restore slash
- mov [ISOFlags],cl ; Restore the flags
- jz .failure ; Did we fail? If so fail for real!
- jmp .look_for_slash ; Otherwise, next level
-
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- ret
-
-;
-; iso_compare_names:
-; Compare the names DS:SI and DS:DI and report if they are
-; equal from an ISO 9660 perspective. SI is the name from
-; the filesystem; CX indicates its length, and ';' terminates.
-; DI is expected to end with a null.
-;
-; Note: clobbers AX, CX, SI, DI; assumes DS == ES == base segment
-;
-iso_compare_names:
- ; First, terminate and canonicalize input filename
- push di
- mov di,ISOFileName
-.canon_loop: jcxz .canon_end
- lodsb
- dec cx
- cmp al,';'
- je .canon_end
- and al,al
- je .canon_end
- stosb
- cmp di,ISOFileNameEnd-1 ; Guard against buffer overrun
- jb .canon_loop
-.canon_end:
- cmp di,ISOFileName
- jbe .canon_done
- cmp byte [di-1],'.' ; Remove terminal dots
- jne .canon_done
- dec di
- jmp short .canon_end
-.canon_done:
- mov [di],byte 0 ; Null-terminate string
- pop di
- mov si,ISOFileName
-.compare:
- lodsb
- mov ah,[di]
- inc di
- and ax,ax
- jz .success ; End of string for both
- and al,al ; Is either one end of string?
- jz .failure ; If so, failure
- and ah,ah
- jz .failure
- or ax,2020h ; Convert to lower case
- cmp al,ah
- je .compare
-.failure: and ax,ax ; ZF = 0 (at least one will be nonzero)
-.success: ret
-
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-; to by ES:DI; ends on encountering any whitespace.
-; DI is preserved.
-;
-; This verifies that a filename is < FILENAME_MAX characters,
-; doesn't contain whitespace, zero-pads the output buffer,
-; and removes trailing dots and redundant slashes,
-; so "repe cmpsb" can do a compare, and the
-; path-searching routine gets a bit of an easier job.
-;
-mangle_name:
- push di
- push bx
- xor ax,ax
- mov cx,FILENAME_MAX-1
- mov bx,di
-
-.mn_loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .mn_end
- cmp al,ah ; Repeated slash?
- je .mn_skip
- xor ah,ah
- cmp al,'/'
- jne .mn_ok
- mov ah,al
-.mn_ok stosb
-.mn_skip: loop .mn_loop
-.mn_end:
- cmp bx,di ; At the beginning of the buffer?
- jbe .mn_zero
- cmp byte [es:di-1],'.' ; Terminal dot?
- je .mn_kill
- cmp byte [es:di-1],'/' ; Terminal slash?
- jne .mn_zero
-.mn_kill: dec di ; If so, remove it
- inc cx
- jmp short .mn_end
-.mn_zero:
- inc cx ; At least one null byte
- xor ax,ax ; Zero-fill name
- rep stosb
- pop bx
- pop di
- ret ; Done
-
-;
-; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
-; filename to the conventional representation. This is needed
-; for the BOOT_IMAGE= parameter for the kernel.
-;
-; DS:SI -> input mangled file name
-; ES:DI -> output buffer
-;
-; On return, DI points to the first byte after the output name,
-; which is set to a null byte.
-;
-unmangle_name: call strcpy
- dec di ; Point to final null byte
- ret
-
-;
-; getfssec: Get multiple clusters from a file, given the file pointer.
-;
-; On entry:
-; ES:BX -> Buffer
-; SI -> File pointer
-; CX -> Cluster count
-; On exit:
-; SI -> File pointer (or 0 on EOF)
-; CF = 1 -> Hit EOF
-; ECX -> Bytes actually read
-;
-getfssec:
- TRACER 'F'
- push ds
- push cs
- pop ds ; DS <- CS
-
- movzx ecx,cx
- cmp ecx,[si+file_left]
- jna .ok_size
- mov ecx,[si+file_left]
-.ok_size:
-
- pushad
- mov eax,[si+file_sector]
- mov bp,cx
- TRACER 'l'
- call getlinsec
- popad
-
- ; ECX[31:16] == 0 here...
- add [si+file_sector],ecx
- sub [si+file_left],ecx
- 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
- jnz .ret ; CF = 0 in this case...
- push eax
- xor eax,eax
- mov [si+file_sector],eax ; Unused
- mov si,ax
- pop eax
- stc
-.ret:
- pop ds
- TRACER 'f'
- ret
; -----------------------------------------------------------------------------
; Common modules
; -----------------------------------------------------------------------------
-%include "getc.inc" ; getc et al
-%include "conio.inc" ; Console I/O
-%include "configinit.inc" ; Initialize configuration
-%include "parseconfig.inc" ; High-level config file handling
-%include "parsecmd.inc" ; Low-level config file handling
-%include "bcopy32.inc" ; 32-bit bcopy
-%include "loadhigh.inc" ; Load a file into high memory
-%include "font.inc" ; VGA font stuff
-%include "graphics.inc" ; VGA graphics
-%include "highmem.inc" ; High memory sizing
-%include "strcpy.inc" ; strcpy()
+%include "common.inc" ; Universal modules
%include "rawcon.inc" ; Console I/O w/o using the console functions
-%include "idle.inc" ; Idle handling
-%include "adv.inc" ; Auxillary Data Vector
%include "localboot.inc" ; Disk-based local boot
; -----------------------------------------------------------------------------
; Begin data section
; -----------------------------------------------------------------------------
- section .data
-
-default_str db 'default', 0
-default_len equ ($-default_str)
-boot_dir db '/boot' ; /boot/isolinux
-isolinux_dir db '/isolinux', 0
-config_name db 'isolinux.cfg', 0
+ section .data16
err_disk_image db 'Cannot load disk image (invalid file)?', CR, LF, 0
-%ifdef DEBUG_MESSAGES
-dbg_rootdir_msg db 'Root directory at LBA = ', 0
-dbg_isodir_msg db 'isolinux directory at LBA = ', 0
-dbg_config_msg db 'About to load config file...', CR, LF, 0
-dbg_configok_msg db 'Configuration file opened...', CR, LF, 0
-%endif
-
;
; Config file keyword table
;
diff --git a/core/kaboom.c b/core/kaboom.c
new file mode 100644
index 00000000..d639915a
--- /dev/null
+++ b/core/kaboom.c
@@ -0,0 +1,16 @@
+/*
+ * kaboom.c
+ */
+
+#include "core.h"
+
+#undef kaboom
+
+__noreturn _kaboom(void)
+{
+ extern void kaboom(void);
+ call16(kaboom, &zero_regs, NULL);
+ /* Do this if kaboom somehow returns... */
+ for (;;)
+ asm volatile("hlt");
+}
diff --git a/core/layout.inc b/core/layout.inc
index 8c2e2485..c67105ad 100644
--- a/core/layout.inc
+++ b/core/layout.inc
@@ -38,11 +38,12 @@ LATEBSS_START equ 0B800h
section .earlybss nobits
section .config write progbits align=4
section .replacestub exec write progbits align=16
+ section .gentextnr exec write nobits align=16
- ; Use .bss for things that doesn't have to be in low memory;
- ; with .bss1 and .bss2 to offload. .earlybss should be used
- ; for things that absolutely have to be below 0x7c00.
- section .bss write nobits align=16
+ ; Use .bss16 for things that doesn't have to be in low memory;
+ ; .earlybss should be used for things that absolutely have
+ ; to be below 0x7c00.
+ section .bss16 write nobits align=16
%if 0 ; IS_PXELINUX
; Warning here: RBFG build 22 randomly overwrites
@@ -54,11 +55,11 @@ LATEBSS_START equ 0B800h
RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
%endif
- section .bss2 write nobits align=16
-
- section .text exec write progbits align=16
+ section .init exec write progbits align=1
+ section .text16 exec write progbits align=1
+ section .textnr exec nowrite progbits align=1
section .bcopyxx exec write progbits align=16
- section .data write progbits align=16
+ section .data16 write progbits align=16
section .adv write nobits align=512
@@ -68,20 +69,26 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
; the spillover from the last fractional sector load.
section .uibss write nobits align=16
- ; Normal bss...
- section .bss1 write nobits align=16
-
; Symbols from linker script
%macro SECINFO 1
extern __%1_start, __%1_lma, __%1_end
extern __%1_len, __%1_dwords
%endmacro
+ SECINFO bss16
+ SECINFO uibss
SECINFO config
SECINFO replacestub
+ SECINFO pm_code
+ SECINFO high_clear
+
+ SECINFO bss
+
+ extern free_high_memory
+
global _start
- section .text
+ section .text16
;
; Segment assignments in the bottom 640K
@@ -89,15 +96,20 @@ RBFG_brainfuck: resb 2048 ; Bigger than an Ethernet packet...
; failure!
;
; 0000h - main code/data segment (and BIOS segment)
-
-xfer_buf_seg equ 1000h
-aux_seg equ 2000h
+;
+; This stuff really should come from the linker...
+;
+ global xfer_buf_seg, core_xfer_buf
+xfer_buf_seg equ 3000h
+core_xfer_buf equ xfer_buf_seg << 4
serial_buf_size equ 4096 ; Should be a power of 2
;
; Contents of aux_seg
;
+ extern aux_seg ; Actual segment assigned by linker
+
struc aux
.fontbuf resb 8192
.serial resb serial_buf_size
@@ -105,7 +117,8 @@ serial_buf_size equ 4096 ; Should be a power of 2
alignb 4096 ; Align the next segment to 4K
endstruc
-aux_seg_end equ aux_seg + (aux_size >> 4)
+ section .auxseg write nobits align=16
+auxseg resb aux_size
;
; Bounce buffer for I/O to high mem
@@ -113,14 +126,11 @@ aux_seg_end equ aux_seg + (aux_size >> 4)
; is somewhat excessive. Sector alignment is obligatory, however.
;
-%if IS_ISOLINUX
-; ISOLINUX doesn't have a block cache yet
-real_mode_seg equ aux_seg_end
-%else
-cache_seg equ aux_seg_end ; 64K area for metadata cache
-real_mode_seg equ cache_seg + 1000h
+ global cache_seg, core_cache_buf
+cache_seg equ 4000h ; 64K area for metadata cache
+core_cache_buf equ cache_seg << 4
+real_mode_seg equ 5000h
pktbuf_seg equ cache_seg ; PXELINUX packet buffers
-%endif
comboot_seg equ real_mode_seg ; COMBOOT image loading zone
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index ba7e8040..23540ea5 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -22,1406 +22,19 @@
;
; ****************************************************************************
-%ifndef IS_MDSLINUX
%define IS_SYSLINUX 1
-%endif
%include "head.inc"
;
; Some semi-configurable constants... change on your own risk.
;
my_id equ syslinux_id
-FILENAME_MAX_LG2 equ 6 ; log2(Max filename size Including final null)
-FILENAME_MAX equ (1<<FILENAME_MAX_LG2) ; Max mangled filename size
-NULLFILE equ 0 ; First char space == null filename
-NULLOFFSET equ 0 ; Position in which to look
-retry_count equ 16 ; How patient are we with the disk?
-%assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
-LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
-MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
-MAX_OPEN equ (1 << MAX_OPEN_LG2)
-
-SECTOR_SHIFT equ 9
-SECTOR_SIZE equ (1 << SECTOR_SHIFT)
-
-DIRENT_SHIFT equ 5
-DIRENT_SIZE equ (1 << DIRENT_SHIFT)
-
-ROOT_DIR_WORD equ 0x002F
-
-;
-; The following structure is used for "virtual kernels"; i.e. LILO-style
-; option labels. The options we permit here are `kernel' and `append
-; Since there is no room in the bottom 64K for all of these, we
-; stick them in high memory and copy them down before we need them.
-;
- struc vkernel
-vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
-vk_rname: resb FILENAME_MAX ; Real name
-vk_appendlen: resw 1
-vk_type: resb 1 ; Type of file
- alignb 4
-vk_append: resb max_cmd_len+1 ; Command line
- alignb 4
-vk_end: equ $ ; Should be <= vk_size
- endstruc
-
-;
-; File structure. This holds the information for each currently open file.
-;
- 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
-
-;
-; Structure for codepage files
-;
- struc cp
-.magic resd 2 ; 8-byte magic number
-.reserved resd 6 ; Reserved for future use
-.uppercase resb 256 ; Internal upper-case table
-.unicode resw 256 ; Unicode matching table
-.unicode_alt resw 256 ; Alternate Unicode matching table
- endstruc
-
-%ifndef DEPEND
-%if (open_file_t_size & (open_file_t_size-1))
-%error "open_file_t is not a power of 2"
-%endif
-%endif
-
-; ---------------------------------------------------------------------------
-; BEGIN CODE
-; ---------------------------------------------------------------------------
-
-;
-; Memory below this point is reserved for the BIOS and the MBR
-;
- section .earlybss
-trackbufsize equ 8192
-trackbuf resb trackbufsize ; Track buffer goes here
- ; ends at 2800h
-
- section .bss
- alignb 4
-FAT resd 1 ; Location of (first) FAT
-RootDirArea resd 1 ; Location of root directory area
-RootDir resd 1 ; Location of root directory proper
-DataArea resd 1 ; Location of data area
-RootDirSize resd 1 ; Root dir size in sectors
-TotalSectors resd 1 ; Total number of sectors
-ClustSize resd 1 ; Bytes/cluster
-ClustMask resd 1 ; Sectors/cluster - 1
-CopySuper resb 1 ; Distinguish .bs versus .bss
-DriveNumber resb 1 ; BIOS drive number
-ClustShift resb 1 ; Shift count for sectors/cluster
-ClustByteShift resb 1 ; Shift count for bytes/cluster
-
- alignb open_file_t_size
-Files resb MAX_OPEN*open_file_t_size
-
-;
-; Common bootstrap code for disk-based derivatives
-;
-%include "diskstart.inc"
-
-;
-; Compute some information about this filesystem.
-;
-
-; First, generate the map of regions
-genfatinfo:
- mov edx,[bxSectors]
- and dx,dx
- jnz .have_secs
- mov edx,[bsHugeSectors]
-.have_secs:
- mov [TotalSectors],edx
-
- mov eax,[bxResSectors]
- mov [FAT],eax ; Beginning of FAT
- mov edx,[bxFATsecs]
- and dx,dx
- jnz .have_fatsecs
- mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
-.have_fatsecs:
- imul edx,[bxFATs]
- add eax,edx
- mov [RootDirArea],eax ; Beginning of root directory
- mov [RootDir],eax ; For FAT12/16 == root dir location
-
- mov edx,[bxRootDirEnts]
- add dx,SECTOR_SIZE/32-1
- shr dx,SECTOR_SHIFT-5
- mov [RootDirSize],edx
- add eax,edx
- mov [DataArea],eax ; Beginning of data area
-
-; Next, generate a cluster size shift count and mask
- mov eax,[bxSecPerClust]
- bsr cx,ax
- mov [ClustShift],cl
- push cx
- add cl,SECTOR_SHIFT
- mov [ClustByteShift],cl
- pop cx
- dec ax
- mov [ClustMask],eax
- inc ax
- shl eax,SECTOR_SHIFT
- mov [ClustSize],eax
-
-;
-; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
-;
-getfattype:
- mov eax,[TotalSectors]
- sub eax,[DataArea]
- shr eax,cl ; cl == ClustShift
- mov cl,nextcluster_fat12-(nextcluster+2)
- cmp eax,4085 ; FAT12 limit
- jb .setsize
- mov cl,nextcluster_fat16-(nextcluster+2)
- cmp eax,65525 ; FAT16 limit
- jb .setsize
- ;
- ; FAT32, root directory is a cluster chain
- ;
- mov cl,[ClustShift]
- mov eax,[bootsec+44] ; Root directory cluster
- sub eax,2
- shl eax,cl
- add eax,[DataArea]
- mov [RootDir],eax
- mov cl,nextcluster_fat28-(nextcluster+2)
- mov byte [SuperSize],superblock_len_fat32
-.setsize:
- mov byte [nextcluster+1],cl
-
-;
-; Common initialization code
-;
-%include "cpuinit.inc"
-%include "init.inc"
-
-;
-; Initialize the metadata cache
-;
- call initcache
-
-;
-; Now, everything is "up and running"... patch kaboom for more
-; verbosity and using the full screen system
-;
- ; E9 = JMP NEAR
- mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
-
-;
-; Now we're all set to start with our *real* business. First load the
-; configuration file (if any) and parse it.
-;
-; In previous versions I avoided using 32-bit registers because of a
-; rumour some BIOSes clobbered the upper half of 32-bit registers at
-; random. I figure, though, that if there are any of those still left
-; they probably won't be trying to install Linux on them...
-;
-; The code is still ripe with 16-bitisms, though. Not worth the hassle
-; to take'm out. In fact, we may want to put them back if we're going
-; to boot ELKS at some point.
-;
-
-;
-; Load configuration file
-;
- mov si,config_name ; Save configuration file name
- mov di,ConfigName
- call strcpy
- mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
-
- mov eax,[RootDir] ; Make the root directory ...
- mov [CurrentDir],eax ; ... the current directory
- mov di,syslinux_cfg1
- push di
- call open
- pop di
- jnz .config_open
- mov di,syslinux_cfg2
- push di
- call open
- pop di
- jnz .config_open
- mov di,syslinux_cfg3
- push di
- call open
- pop di
- jz no_config_file
-.config_open:
- push si
- mov si,di
- push si
- mov di,CurrentDirName
- ; This is inefficient as it will copy more than needed
- ; but not by too much
- call strcpy
- mov ax,config_name ;Cut it down
- pop si
- sub ax,si
- mov di,CurrentDirName
- add di,ax
- mov byte [di],0
- pop si
- mov eax,[PrevDir] ; Make the directory with syslinux.cfg ...
- mov [CurrentDir],eax ; ... the current directory
-
-;
-; Now we have the config file open. Parse the config file and
-; run the user interface.
-;
-%include "ui.inc"
-
-;
-; allocate_file: Allocate a file structure
-;
-; If successful:
-; ZF set
-; BX = file pointer
-; In unsuccessful:
-; ZF clear
-;
-allocate_file:
- TRACER 'a'
- push cx
- mov bx,Files
- mov cx,MAX_OPEN
-.check: cmp dword [bx], byte 0
- je .found
- add bx,open_file_t_size ; ZF = 0
- loop .check
- ; ZF = 0 if we fell out of the loop
-.found: pop cx
- ret
-
-;
-; alloc_fill_dir:
-; Allocate then fill a file structure for a directory starting in
-; sector EAX.
-;
-; Assumes DS == ES == CS.
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; If unsuccessful
-; ZF set
-; EAX clobbered
-;
-alloc_fill_dir:
- push bx
- call allocate_file
- jnz .alloc_failure
-.found:
- mov si,bx
- mov [si+file_sector],eax ; Current sector
- mov dword [si+file_bytesleft],0 ; Current offset
- mov [si+file_left],eax ; Beginning sector
- pop bx
- ret
-
-.alloc_failure:
- pop bx
- xor eax,eax ; ZF <- 1
- ret
-
-;
-; search_dos_dir:
-; Search a specific directory for a pre-mangled filename in
-; MangledBuf, in the directory starting in sector EAX.
-;
-; NOTE: This file considers finding a zero-length file an
-; error. This is so we don't have to deal with that special
-; case elsewhere in the program (most loops have the test
-; at the end).
-;
-; Assumes DS == ES == CS.
-;
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length (MAY BE ZERO!)
-; DL = file attribute
-; DH = clobbered
-; If unsuccessful
-; ZF set
-; EAX, SI, DX clobbered
-;
-
-search_dos_dir:
- push bx
- call allocate_file
- jnz .alloc_failure
-
- push cx
- push gs
- push es
- push ds
- pop es ; ES = DS
-
- ; Compute the value of a possible VFAT longname
- ; "last" entry (which, of course, comes first...)
- push ax
- push dx
- mov ax,[NameLen]
- add ax,12
- xor dx,dx
- mov cx,13
- div cx
- or al,40h
- mov [VFATInit],al
- mov [VFATNext],al
- pop dx
- pop ax
-
-.scansector:
- ; EAX <- directory sector to scan
- call getcachesector
- ; GS:SI now points to this sector
-
- mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
-.scanentry:
- cmp byte [gs:si],0
- jz .failure ; Hit directory high water mark
- cmp word [gs:si+11],0Fh ; Long filename
- jne .short_entry
-
- ; Process a VFAT long entry
- pusha
- mov al,[gs:si]
- cmp al,[VFATNext]
- jne .not_us
- mov bl,[gs:si+13]
- test al,40h
- jz .match_csum
- ; Get the initial checksum value
- mov [VFATCsum],bl
- jmp .done_csum
-.match_csum:
- cmp bl,[VFATCsum]
- jne .not_us ; Checksum mismatch
-.done_csum:
- and ax,03fh
- jz .not_us ; Can't be zero...
- dec ax
- mov [VFATNext],al ; Optimistically...
- mov bx,ax
- shl bx,2 ; *4
- add ax,bx ; *5
- add bx,bx ; *8
- add bx,ax ; *13
- cmp bx,[NameLen]
- jae .not_us
- mov di,[NameStart]
- inc si
- mov cx,13
-.vfat_cmp:
- gs lodsw
- push bx
- cmp bx,[NameLen]
- jae .vfat_tail
- movzx bx,byte [bx+di]
- add bx,bx
- cmp ax,[cp_unicode+bx] ; Primary case
- je .ucs_ok
- cmp ax,[cp_unicode_alt+bx] ; Alternate case
- je .ucs_ok
- ; Mismatch...
- jmp .not_us_pop
-.vfat_tail:
- ; *AT* the end we should have 0x0000, *AFTER* the end
- ; we should have 0xFFFF...
- je .vfat_end
- inc ax ; 0xFFFF -> 0x0000
-.vfat_end:
- and ax,ax
- jnz .not_us_pop
-.ucs_ok:
- pop bx
- inc bx
- cmp cx,3
- je .vfat_adj_add2
- cmp cx,9
- jne .vfat_adj_add0
-.vfat_adj_add3: inc si
-.vfat_adj_add2: inc si
-.vfat_adj_add1: inc si
-.vfat_adj_add0:
- loop .vfat_cmp
- ; Okay, if we got here we had a match on this particular
- ; entry... live to see another one.
- popa
- jmp .next_entry
-
-.not_us_pop:
- pop bx
-.not_us:
- popa
- jmp .nomatch
-
-.short_entry:
- test byte [gs:si+11],8 ; Ignore volume labels
- jnz .nomatch
-
- cmp byte [VFATNext],0 ; Do we have a longname match?
- jne .no_long_match
-
- ; We already have a VFAT longname match, however,
- ; the match is only valid if the checksum matches
- push cx
- push si
- push ax
- xor ax,ax
- mov cx,11
-.csum_loop:
- gs lodsb
- ror ah,1
- add ah,al
- loop .csum_loop
- cmp ah,[VFATCsum]
- pop ax
- pop si
- pop cx
- je .found ; Got a match on longname
-
-.no_long_match: ; Look for a shortname match
- push cx
- push si
- push di
- mov di,MangledBuf
- mov cx,11
- gs repe cmpsb
- pop di
- pop si
- pop cx
- je .found
-.nomatch:
- ; Reset the VFAT matching state machine
- mov dh,[VFATInit]
- mov [VFATNext],dh
-.next_entry:
- add si,32
- dec cx
- jnz .scanentry
-
- call nextsector
- jnc .scansector ; CF is set if we're at end
-
- ; If we get here, we failed
-.failure:
- pop es
- pop gs
- pop cx
-.alloc_failure:
- pop bx
- xor eax,eax ; ZF <- 1
- ret
-.found:
- mov eax,[gs:si+28] ; File size
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [bx+4],eax ; Sector count
-
- mov cl,[ClustShift]
- mov dx,[gs:si+20] ; High cluster word
- shl edx,16
- mov dx,[gs:si+26] ; Low cluster word
- sub edx,2
- shl edx,cl
- add edx,[DataArea]
- mov [bx],edx ; Starting sector
-
- mov eax,[gs:si+28] ; File length again
- mov dl,[gs:si+11] ; File attribute
- mov si,bx ; File pointer...
- and si,si ; ZF <- 0
-
- pop es
- pop gs
- pop cx
- pop bx
- ret
-
- section .data
+ section .rodata
alignz 4
- ; Note: we have no use of the first 32 bytes (header),
- ; nor of the folloing 32 bytes (case mapping of control
- ; characters), as long as we adjust the offsets appropriately.
-codepage equ $-(32+32)
-codepage_data: incbin "codepage.cp",32+32
-cp_uppercase equ codepage+cp.uppercase
-cp_unicode equ codepage+cp.unicode
-cp_unicode_alt equ codepage+cp.unicode_alt
-codepage_end equ $
-
- section .text
-;
-; Input: UCS-2 character in AX
-; Output: Single byte character in AL, ZF = 1
-; On failure, returns ZF = 0
-;
-ucs2_to_cp:
- push es
- push di
- push cx
- push cs
- pop es
- mov di,cp_unicode
- mov cx,512
- repne scasw
- xchg ax,cx
- pop cx
- pop di
- pop es
- not ax ; Doesn't change the flags!
- ret
-
- section .bss
-VFATInit resb 1
-VFATNext resb 1
-VFATCsum resb 1
-
- section .text
-;
-; close_file:
-; Deallocates a file structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_file:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_sector
- xor si,si
-.closed: ret
-
-;
-; close_dir:
-; Deallocates a directory structure (pointer in SI)
-; Assumes CS == DS.
-;
-close_dir:
- and si,si
- jz .closed
- mov dword [si],0 ; First dword == file_sector
- xor si,si
-.closed: ret
-
-;
-; searchdir:
-;
-; Open a file
-;
-; On entry:
-; DS:DI = filename
-; If successful:
-; ZF clear
-; SI = file pointer
-; EAX = file length in bytes
-; If unsuccessful
-; ZF set
-;
-; Assumes CS == DS == ES, and trashes BX and CX.
-;
-searchdir:
- mov eax,[CurrentDir]
- cmp byte [di],'/' ; Root directory?
- jne .notroot
- mov eax,[RootDir]
- inc di
-.notroot:
-
-.pathwalk:
- push eax ; <A> Current directory sector
- mov si,di
-.findend:
- lodsb
- cmp al,' '
- jbe .endpath
- cmp al,'/'
- jne .findend
-.endpath:
- xchg si,di ; GRC: si begin; di end[ /]+1
- pop eax ; <A> Current directory sector
-
- ; GRC Here I need to check if di-1 = si which signifies
- ; we have the desired directory in EAX
- ; What about where the file name = "."; later
- mov dx,di
- dec dx
- cmp dx,si
- jz .founddir
-
- mov [PrevDir],eax ; Remember last directory searched
-
- push di
- call mangle_dos_name ; MangledBuf <- component
- call search_dos_dir
- pop di
- jz .notfound ; Pathname component missing
-
- cmp byte [di-1],'/' ; Do we expect a directory
- je .isdir
-
- ; Otherwise, it should be a file
-.isfile:
- test dl,18h ; Subdirectory|Volume Label
- jnz .badfile ; If not a file, it's a bad thing
-
- ; SI and EAX are already set
- 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!
-
- ; If we expected a directory, it better be one...
-.isdir:
- test dl,10h ; Subdirectory
- jz .badfile
-
- xor eax,eax
- xchg eax,[si+file_sector] ; Get sector number and free file structure
- jmp .pathwalk ; Walk the next bit of the path
-
- ; Found the desired directory; ZF set but EAX not 0
-.founddir:
- ret
-
-.badfile:
- xor eax,eax
- mov [si],eax ; Free file structure
-
-.notfound:
- xor eax,eax ; Zero out EAX
- ret
-
-;
-; readdir: Read one file from a directory
-;
-; ES:DI -> String buffer (filename)
-; DS:SI -> Pointer to open_file_t
-; DS Must be the SYSLINUX Data Segment
-;
-; Returns the file's name in the filename string buffer
-; EAX returns the file size
-; EBX returns the beginning sector (currently without offsetting)
-; DL returns the file type
-; The directory handle's data is incremented to reflect a name read.
-;
-readdir:
- push ecx
- push bp ; Using bp to transfer between segment registers
- push si
- push es
- push fs ; Using fs to store the current es (from COMBOOT)
- push gs
- mov bp,es
- mov fs,bp
- cmp si,0
- jz .fail
-.load_handle:
- mov eax,[ds:si+file_sector] ; Current sector
- mov ebx,[ds:si+file_bytesleft] ; Current offset
- cmp eax,0
- jz .fail
-.fetch_cache:
- call getcachesector
-.move_current:
- add si,bx ; Resume last position in sector
- mov ecx,SECTOR_SIZE ; 0 out high part
- sub cx,bx
- shr cx,5 ; Number of entries left
-.scanentry:
- cmp byte [gs:si],0
- jz .fail
- cmp word [gs:si+11],0Fh ; Long filename
- jne .short_entry
-
-.vfat_entry:
- push eax
- push ecx
- push si
- push di
-.vfat_ln_info: ; Get info about the line that we're on
- mov al,[gs:si]
- test al,40h
- jz .vfat_tail_ln
- and al,03Fh
- mov ah,1 ; On beginning line
- jmp .vfat_ck_ln
-
-.vfat_tail_ln: ; VFAT tail line processing (later in VFAT, head in name)
- test al,80h ; Invalid data?
- jnz .vfat_abort
- mov ah,0 ; Not on beginning line
- cmp dl,al
- jne .vfat_abort ; Is this the entry we need?
- mov bl,[gs:si+13]
- cmp bl,[VFATCsum]
- je .vfat_cp_ln
- jmp .vfat_abort
-
-.vfat_ck_ln: ; Load this line's VFAT CheckSum
- mov bl,[gs:si+13]
- mov [VFATCsum],bl
-.vfat_cp_ln: ; Copy VFAT line
- dec al ; Store the next line we need
- mov dx,ax ; Use DX to store the progress
- mov cx,13 ; 13 characters per VFAT DIRENT
- cbw ; AH <- 0
- mul cl ; Offset for DI
- add di,ax ; Increment DI
- inc si ; Align to the real characters
-.vfat_cp_chr:
- gs lodsw ; Unicode here!!
- call ucs2_to_cp ; Convert to local codepage
- jnz .vfat_abort ; Use short name if character not on codepage
- stosb ; CAN NOT OVERRIDE es
- cmp al,0
- jz .vfat_find_next ; Null-terminated string; don't process more
- cmp cx,3
- je .vfat_adj_add2
- cmp cx,9
- jne .vfat_adj_add0
-.vfat_adj_add3: inc si
-.vfat_adj_add2: inc si
-.vfat_adj_add1: inc si
-.vfat_adj_add0:
- loop .vfat_cp_chr
- cmp dh,1 ; Is this the first round?
- jnz .vfat_find_next
-.vfat_null_term: ; Need to null-terminate if first line as we rolled over the end
- mov al,0
- stosb
-
-.vfat_find_next: ;Find the next part of the name
- pop di
- pop si
- pop ecx
- pop eax
- cmp dl,0
- jz .vfat_find_info ; We're done with the name
- add si,DIRENT_SIZE
- dec cx
- jnz .vfat_entry
- call nextsector
- jnc .vfat_entry ; CF is set if we're at end
- jmp .fail
-.vfat_find_info: ; Fetch next entry for the size/"INode"
- add si,DIRENT_SIZE
- dec cx
- jnz .get_info
- call nextsector
- jnc .get_info ; CF is set if we're at end
- jmp .fail
-.vfat_abort: ; Something went wrong, skip
- pop di
- pop si
- pop ecx
- pop eax
- jmp .skip_entry
-
-.short_entry:
- test byte [gs:si+11],8 ; Ignore volume labels //HERE
- jnz .skip_entry
- mov edx,eax ;Save current sector
- push cx
- push si
- push di
- mov cx,8
-.short_file:
- gs lodsb
- cmp al,'.'
- jz .short_dot
-.short_file_loop:
- cmp al,' '
- jz .short_skip_bs
- stosb
- loop .short_file_loop
- jmp .short_period
-.short_skip_bs: ; skip blank spaces in FILENAME (before EXT)
- add si,cx
- dec si
-.short_period:
- mov al,'.'
- stosb
- mov cx,3
-.short_ext:
- gs lodsb
- cmp al,' '
- jz .short_done
- stosb
- loop .short_ext
- jmp .short_done
-.short_dot:
- stosb
- gs lodsb
- cmp al,' '
- jz .short_done
- stosb
-.short_done:
- mov al,0 ; Null-terminate the short strings
- stosb
- pop di
- pop si
- pop cx
- mov eax,edx
-.get_info:
- mov ebx,[gs:si+28] ; length
- mov dl,[gs:si+11] ; type
-.next_entry:
- add si,DIRENT_SIZE
- dec cx
- jnz .store_offset
- call nextsector
- jnc .store_sect ; CF is set if we're at end
- jmp .fail
-
-.skip_entry:
- add si,DIRENT_SIZE
- dec cx
- jnz .scanentry
- call nextsector
- jnc .scanentry ; CF is set if we're at end
- jmp .fail
-
-.store_sect:
- pop gs
- pop fs
- pop es
- pop si
- mov [ds:si+file_sector],eax
- mov eax,0 ; Now at beginning of new sector
- jmp .success
-
-.store_offset:
- pop gs
- pop fs
- pop es
- pop si ; cx=num remain; SECTOR_SIZE-(cx*32)=cur pos
- shl ecx,DIRENT_SHIFT
- mov eax,SECTOR_SIZE
- sub eax,ecx
- and eax,0ffffh
-
-.success:
- mov [ds:si+file_bytesleft],eax
- ; "INode" number = ((CurSector-RootSector)*SECTOR_SIZE + Offset)/DIRENT_SIZE)
- mov ecx,eax
- mov eax,[ds:si+file_sector]
- sub eax,[RootDir]
- shl eax,SECTOR_SHIFT
- add eax,ecx
- shr eax,DIRENT_SHIFT
- dec eax
- xchg eax,ebx ; -> EBX=INode, EAX=FileSize
- jmp .done
-
-.fail:
- pop gs
- pop fs
- pop es
- pop si
- call close_dir
- xor eax,eax
- stc
-.done:
- pop bp
- pop ecx
-.end:
- ret
-
- section .bss
- alignb 4
-CurrentDir resd 1 ; Current directory
-PrevDir resd 1 ; Last scanned directory
-
- section .text
-
-;
-;
-; kaboom2: once everything is loaded, replace the part of kaboom
-; starting with "kaboom.patch" with this part
-
-kaboom2:
- mov si,err_bootfailed
- call writestr
- cmp byte [kaboom.again+1],18h ; INT 18h version?
- je .int18
- call getchar
- call vgaclearmode
- int 19h ; And try once more to boot...
-.norge: jmp short .norge ; If int 19h returned; this is the end
-.int18:
- call vgaclearmode
- int 18h
-.noreg: jmp short .noreg ; Nynorsk
-
-;
-; mangle_name: Mangle a filename pointed to by DS:SI into a buffer pointed
-; to by ES:DI; ends on encountering any whitespace.
-; DI is preserved.
-;
-; This verifies that a filename is < FILENAME_MAX characters,
-; doesn't contain whitespace, zero-pads the output buffer,
-; and removes trailing dots and redundant slashes, plus changes
-; backslashes to forward slashes,
-; so "repe cmpsb" can do a compare, and the path-searching routine
-; gets a bit of an easier job.
-;
-;
-mangle_name:
- push di
- push bx
- xor ax,ax
- mov cx,FILENAME_MAX-1
- mov bx,di
-
-.mn_loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .mn_end
- cmp al,'\' ; Backslash?
- jne .mn_not_bs
- mov al,'/' ; Change to forward slash
-.mn_not_bs:
- cmp al,ah ; Repeated slash?
- je .mn_skip
- xor ah,ah
- cmp al,'/'
- jne .mn_ok
- mov ah,al
-.mn_ok stosb
-.mn_skip: loop .mn_loop
-.mn_end:
- cmp bx,di ; At the beginning of the buffer?
- jbe .mn_zero
- cmp byte [es:di-1],'.' ; Terminal dot?
- je .mn_kill
- cmp byte [es:di-1],'/' ; Terminal slash?
- jne .mn_zero
-.mn_kill: dec di ; If so, remove it
- inc cx
- jmp short .mn_end
-.mn_zero:
- inc cx ; At least one null byte
- xor ax,ax ; Zero-fill name
- rep stosb
- pop bx
- pop di
- ret ; Done
-
-;
-; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
-; filename to the conventional representation. This is needed
-; for the BOOT_IMAGE= parameter for the kernel.
-; NOTE: A 13-byte buffer is mandatory, even if the string is
-; known to be shorter.
-;
-; DS:SI -> input mangled file name
-; ES:DI -> output buffer
-;
-; On return, DI points to the first byte after the output name,
-; which is set to a null byte.
-;
-unmangle_name: call strcpy
- dec di ; Point to final null byte
- ret
-
-;
-; mangle_dos_name:
-; Mangle a DOS filename component pointed to by DS:SI
-; into [MangledBuf]; ends on encountering any whitespace or
-; slash.
-;
-; WARNING: saves pointers into the buffer for longname
-; matches!
-;
-; Assumes CS == DS == ES.
-;
-
-mangle_dos_name:
- pusha
- mov di,MangledBuf
- mov [NameStart],si
+ROOT_FS_OPS:
+ extern vfat_fs_ops
+ dd vfat_fs_ops
+ dd 0
- mov cx,11 ; # of bytes to write
- mov bx,cp_uppercase ; Case-conversion table
-.loop:
- lodsb
- cmp al,' ' ; If control or space, end
- jna .end
- cmp al,'/' ; Slash, too
- je .end
- cmp al,'.' ; Period -> space-fill
- je .is_period
- xlatb ; Convert to upper case
- mov ah,cl ; If the first byte (only!)...
- cmp ax,0BE5h ; ... equals E5 hex ...
- jne .charok
- mov al,05h ; ... change it to 05 hex
-.charok: stosb
- loop .loop ; Don't continue if too long
- ; Find the end for the benefit of longname search
-.find_end:
- lodsb
- cmp al,' '
- jna .end
- cmp al,'/'
- jne .find_end
-.end:
- dec si
- sub si,[NameStart]
- mov [NameLen],si
- mov al,' ' ; Space-fill name
- rep stosb ; Doesn't do anything if CX=0
- popa
- ret ; Done
-
-.is_period:
- mov al,' ' ; We need to space-fill
-.period_loop: cmp cx,3 ; If <= 3 characters left
- jbe .loop ; Just ignore it
- stosb ; Otherwise, write a space
- loop .period_loop ; Dec CX and *always* jump
-
- section .bss
- alignb 2
-NameStart resw 1
-NameLen resw 1
-MangledBuf resb 11
-
- section .text
-;
-; getfssec_edx: Get multiple sectors from a file
-;
-; This routine makes sure the subtransfers do not cross a 64K boundary,
-; and will correct the situation if it does, UNLESS *sectors* cross
-; 64K boundaries.
-;
-; ES:BX -> Buffer
-; EDX -> Current sector number
-; CX -> Sector count (0FFFFh = until end of file)
-; Must not exceed the ES segment
-; Returns EDX=0, CF=1 on EOF (not necessarily error)
-; All arguments are advanced to reflect data read.
-;
-getfssec_edx:
- push ebp
- push eax
-.getfragment:
- xor ebp,ebp ; Fragment sector count
- push edx ; Starting sector pointer
-.getseccnt:
- inc bp
- dec cx
- jz .do_read
- xor eax,eax
- mov ax,es
- shl ax,4
- add ax,bx ; Now AX = how far into 64K block we are
- not ax ; Bytes left in 64K block
- inc eax
- shr eax,SECTOR_SHIFT ; Sectors left in 64K block
- cmp bp,ax
- jnb .do_read ; Unless there is at least 1 more sector room...
- mov eax,edx ; Current sector
- inc edx ; Predict it's the linearly next sector
- call nextsector
- jc .do_read
- cmp edx,eax ; Did it match?
- jz .getseccnt
-.do_read:
- pop eax ; Starting sector pointer
- call getlinsecsr
- lea eax,[eax+ebp-1] ; This is the last sector actually read
- shl bp,9
- add bx,bp ; Adjust buffer pointer
- call nextsector
- jc .eof
- mov edx,eax
- and cx,cx
- jnz .getfragment
-.done:
- pop eax
- pop ebp
- ret
-.eof:
- xor edx,edx
- stc
- jmp .done
-
-;
-; getfssec: Get multiple sectors from a file
-;
-; Same as above, except SI is a pointer to a open_file_t
-;
-; ES:BX -> Buffer
-; DS:SI -> Pointer to open_file_t
-; 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
- push edx ; Zero-extended CX
- cmp edx,[si+file_left]
- jbe .sizeok
- mov edx,[si+file_left]
- mov cx,dx
-.sizeok:
- sub [si+file_left],edx
- mov edx,[si+file_sector]
- call getfssec_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
-; pointed at in the FAT tables. CF=0 on return if end of file.
-;
-nextcluster:
- jmp strict short nextcluster_fat28 ; This gets patched
-
-nextcluster_fat12:
- push eax
- push edx
- push bx
- push cx
- push si
- mov edx,edi
- shr edi,1
- pushf ; Save the shifted-out LSB (=CF)
- add edx,edi
- mov eax,edx
- shr eax,9
- call getfatsector
- mov bx,dx
- and bx,1FFh
- mov cl,[gs:si+bx]
- inc edx
- mov eax,edx
- shr eax,9
- call getfatsector
- mov bx,dx
- and bx,1FFh
- mov ch,[gs:si+bx]
- popf
- jnc .even
- shr cx,4
-.even: and cx,0FFFh
- movzx edi,cx
- cmp di,0FF0h
- pop si
- pop cx
- pop bx
- pop edx
- pop eax
- ret
-
-;
-; FAT16 decoding routine.
-;
-nextcluster_fat16:
- push eax
- push si
- push bx
- mov eax,edi
- shr eax,SECTOR_SHIFT-1
- call getfatsector
- mov bx,di
- add bx,bx
- and bx,1FEh
- movzx edi,word [gs:si+bx]
- cmp di,0FFF0h
- pop bx
- pop si
- pop eax
- ret
-;
-; FAT28 ("FAT32") decoding routine.
-;
-nextcluster_fat28:
- push eax
- push si
- push bx
- mov eax,edi
- shr eax,SECTOR_SHIFT-2
- call getfatsector
- mov bx,di
- add bx,bx
- add bx,bx
- and bx,1FCh
- mov edi,dword [gs:si+bx]
- and edi,0FFFFFFFh ; 28 bits only
- cmp edi,0FFFFFF0h
- pop bx
- pop si
- pop eax
- ret
-
-;
-; nextsector: Given a sector in EAX on input, return the next sector
-; of the same filesystem object, which may be the root
-; directory or a cluster chain. Returns EOF.
-;
-; Assumes CS == DS.
-;
-nextsector:
- push edi
- push edx
- mov edx,[DataArea]
- mov edi,eax
- sub edi,edx
- jae .isdata
-
- ; Root directory
- inc eax
- cmp eax,edx
- cmc
- jmp .done
-
-.isdata:
- not edi
- test edi,[ClustMask]
- jz .endcluster
-
- ; It's not the final sector in a cluster
- inc eax
- jmp .done
-
-.endcluster:
- push gs ; nextcluster trashes gs
- push cx
- not edi
- mov cl,[ClustShift]
- shr edi,cl
- add edi,2
-
- ; Now EDI contains the cluster number
- call nextcluster
- cmc
- jc .exit ; There isn't anything else...
-
- ; New cluster number now in EDI
- sub edi,2
- shl edi,cl ; CF <- 0, unless something is very wrong
- lea eax,[edi+edx]
-.exit:
- pop cx
- pop gs
-.done:
- pop edx
- pop edi
- ret
-
-;
-; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
-; and return a pointer in GS:SI, loading it if needed.
-;
-; Assumes CS == DS.
-;
-getfatsector:
- add eax,[FAT] ; FAT starting address
- jmp getcachesector
-
-; -----------------------------------------------------------------------------
-; Common modules
-; -----------------------------------------------------------------------------
-
-%include "getc.inc" ; getc et al
-%include "conio.inc" ; Console I/O
-%include "plaincon.inc" ; writechr
-%include "writestr.inc" ; String output
-%include "writehex.inc" ; Hexadecimal output
-%include "configinit.inc" ; Initialize configuration
-%include "parseconfig.inc" ; High-level config file handling
-%include "parsecmd.inc" ; Low-level config file handling
-%include "bcopy32.inc" ; 32-bit bcopy
-%include "loadhigh.inc" ; Load a file into high memory
-%include "font.inc" ; VGA font stuff
-%include "graphics.inc" ; VGA graphics
-%include "highmem.inc" ; High memory sizing
-%include "strcpy.inc" ; strcpy()
-%include "cache.inc" ; Metadata disk cache
-%include "idle.inc" ; Idle handling
-%include "adv.inc" ; Auxillary Data Vector
-%include "localboot.inc" ; Disk-based local boot
-
-; -----------------------------------------------------------------------------
-; Begin data section
-; -----------------------------------------------------------------------------
-
- section .data
-copyright_str db ' Copyright (C) 1994-'
- asciidec YEAR
- db ' H. Peter Anvin et al', CR, LF, 0
-err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
- db 'a key to continue.', CR, LF, 0
-syslinux_cfg1 db '/boot' ; /boot/syslinux/syslinux.cfg
-syslinux_cfg2 db '/syslinux' ; /syslinux/syslinux.cfg
-syslinux_cfg3 db '/' ; /syslinux.cfg
-config_name db 'syslinux.cfg', 0 ; syslinux.cfg
-
-;
-; Config file keyword table
-;
-%include "keywords.inc"
-
-;
-; Extensions to search for (in *forward* order).
-;
-exten_table: db '.cbt' ; COMBOOT (specific)
- db '.bss' ; Boot Sector (add superblock)
- db '.bs', 0 ; Boot Sector
- db '.com' ; COMBOOT (same as DOS)
- db '.c32' ; COM32
-exten_table_end:
- dd 0, 0 ; Need 8 null bytes here
-
-;
-; Misc initialized (data) variables
-;
-%ifdef debug ; This code for debugging only
-debug_magic dw 0D00Dh ; Debug code sentinel
-%endif
-
- alignz 4
-BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
-BufSafeBytes dw trackbufsize ; = how many bytes?
-%ifndef DEPEND
-%if ( trackbufsize % SECTOR_SIZE ) != 0
-%error trackbufsize must be a multiple of SECTOR_SIZE
-%endif
-%endif
+%include "diskfs.inc"
diff --git a/core/loadhigh.inc b/core/loadhigh.inc
index 8ff9da1c..63ab0010 100644
--- a/core/loadhigh.inc
+++ b/core/loadhigh.inc
@@ -17,7 +17,7 @@
;; Load a file into high memory
;;
- section .text
+ section .text16
;
; load_high: loads (the remainder of) a file into high memory.
@@ -69,7 +69,7 @@ load_high:
push edi ; <C> Target buffer
mov cx,ax
xor bx,bx ; ES:0
- call getfssec ; Load the data into xfer_buf_seg
+ pm_call getfssec ; Load the data into xfer_buf_seg
pop edi ; <C> Target buffer
pushf ; <C> EOF status
lea ebx,[edi+ecx] ; End of data
@@ -103,12 +103,12 @@ load_high:
.overflow: mov si,err_nohighmem
jmp abort_load
- section .data
+ section .data16
err_nohighmem db CR, LF
db 'Not enough memory to load specified image.', CR, LF, 0
- section .bss
+ section .bss16
alignb 2
PauseBird resw 1
- section .text
+ section .text16
diff --git a/core/localboot.inc b/core/localboot.inc
index 03d5cfd9..a66cf206 100644
--- a/core/localboot.inc
+++ b/core/localboot.inc
@@ -22,7 +22,7 @@
; Boot a specified local disk. AX specifies the BIOS disk number; or
; -1 in case we should execute INT 18h ("next device.")
;
- section .text
+ section .text16
local_boot:
call vgaclearmode
@@ -68,9 +68,9 @@ local_boot:
int 18h ; Hope this does the right thing...
jmp kaboom ; If we returned, oh boy...
- section .data
+ section .data16
localboot_msg db 'Booting from local disk...', CR, LF, 0
- section .text
+ section .text16
%endif ; HAS_LOCALBOOT
diff --git a/core/lzo/enter.ash b/core/lzo/enter.ash
new file mode 100644
index 00000000..49c455d6
--- /dev/null
+++ b/core/lzo/enter.ash
@@ -0,0 +1,89 @@
+/* enter.ash -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ pushl %ebp
+ pushl %edi
+ pushl %esi
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ subl $12,%esp
+
+ cld
+
+ movl INP,%esi
+ movl OUTP,%edi
+#if defined(N_3_EBP)
+ movl $3,%ebp
+#endif
+#if defined(N_255_EBP)
+ movl $255,%ebp
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+#if defined(INIT_OVERRUN)
+ INIT_OVERRUN
+# undef INIT_OVERRUN
+#endif
+ leal -3(%esi),%eax /* 3 == length of EOF code */
+ addl INS,%eax
+ movl %eax,INEND
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+#if defined(INIT_OVERRUN)
+ INIT_OVERRUN
+# undef INIT_OVERRUN
+#endif
+ movl %edi,%eax
+ movl OUTS,%edx
+ addl (%edx),%eax
+ movl %eax,OUTEND
+#endif
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/leave.ash b/core/lzo/leave.ash
new file mode 100644
index 00000000..9550b46f
--- /dev/null
+++ b/core/lzo/leave.ash
@@ -0,0 +1,114 @@
+/* leave.ash -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+/* check uncompressed size */
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+ cmpl OUTEND,%edi
+ ja .L_output_overrun
+#endif
+
+/* check compressed size */
+ movl INP,%edx
+ addl INS,%edx
+ cmpl %edx,%esi /* check compressed size */
+ ja .L_input_overrun
+ jb .L_input_not_consumed
+
+.L_leave:
+ subl OUTP,%edi /* write back the uncompressed size */
+ movl OUTS,%edx
+ movl %edi,(%edx)
+
+ negl %eax
+ addl $12,%esp
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %esi
+ popl %edi
+ popl %ebp
+#if 1
+ ret
+#else
+ jmp .L_end
+#endif
+
+
+.L_error:
+ movl $1,%eax /* LZO_E_ERROR */
+ jmp .L_leave
+
+.L_input_not_consumed:
+ movl $8,%eax /* LZO_E_INPUT_NOT_CONSUMED */
+ jmp .L_leave
+
+.L_input_overrun:
+ movl $4,%eax /* LZO_E_INPUT_OVERRUN */
+ jmp .L_leave
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+.L_output_overrun:
+ movl $5,%eax /* LZO_E_OUTPUT_OVERRUN */
+ jmp .L_leave
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+.L_lookbehind_overrun:
+ movl $6,%eax /* LZO_E_LOOKBEHIND_OVERRUN */
+ jmp .L_leave
+#endif
+
+#if defined(LZO_DEBUG)
+.L_assert_fail:
+ movl $99,%eax
+ jmp .L_leave
+#endif
+
+.L_end:
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/lzo1c_d.ash b/core/lzo/lzo1c_d.ash
new file mode 100644
index 00000000..9969c86a
--- /dev/null
+++ b/core/lzo/lzo1c_d.ash
@@ -0,0 +1,184 @@
+/* lzo1c_d.ash -- assembler implementation of the LZO1C decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ ALIGN3
+.L1:
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ cmpb $32,%al
+ jnb .LMATCH
+
+ orb %al,%al
+ jz .L12
+ movl %eax,%ecx
+.LIT:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ rep
+ movsb
+.LM1:
+ movb (%esi),%al
+ incl %esi
+
+ cmpb $32,%al
+ jb .LM2
+.LMATCH:
+ cmpb $64,%al
+ jb .LN3
+
+ movl %eax,%ecx
+ andb $31,%al
+ leal -1(%edi),%edx
+ shrl $5,%ecx
+ subl %eax,%edx
+ movb (%esi),%al
+ incl %esi
+
+ shll $5,%eax
+ subl %eax,%edx
+ incl %ecx
+ xchgl %esi,%edx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%ebx)
+ rep
+ movsb
+ movl %edx,%esi
+ jmp .L1
+
+ ALIGN3
+.L12:
+ LODSB
+ leal 32(%eax),%ecx
+ cmpb $248,%al
+ jb .LIT
+
+ movl $280,%ecx
+ subb $248,%al
+ jz .L11
+ xchgl %eax,%ecx
+ xorb %al,%al
+ shll %cl,%eax
+ xchgl %eax,%ecx
+.L11:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ rep
+ movsb
+ jmp .L1
+
+ ALIGN3
+.LM2:
+ leal -1(%edi),%edx
+ subl %eax,%edx
+ LODSB
+ shll $5,%eax
+ subl %eax,%edx
+ xchgl %esi,%edx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP(4(%edi),%ebx)
+ movsb
+ movsb
+ movsb
+ movl %edx,%esi
+ movsb
+ xorl %eax,%eax
+ jmp .LM1
+.LN3:
+ andb $31,%al
+ movl %eax,%ecx
+ jnz .LN6
+ movb $31,%cl
+.LN4:
+ LODSB
+ orb %al,%al
+ jnz .LN5
+ addl N_255,%ecx
+ jmp .LN4
+
+ ALIGN3
+.LN5:
+ addl %eax,%ecx
+.LN6:
+ movb (%esi),%al
+ incl %esi
+
+ movl %eax,%ebx
+ andb $63,%al
+ movl %edi,%edx
+ subl %eax,%edx
+
+ movb (%esi),%al
+ incl %esi
+
+ shll $6,%eax
+ subl %eax,%edx
+ cmpl %edi,%edx
+ jz .LEOF
+
+ xchgl %edx,%esi
+ leal 3(%ecx),%ecx
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%eax)
+ rep
+ movsb
+
+ movl %edx,%esi
+ xorl %eax,%eax
+ shrl $6,%ebx
+ movl %ebx,%ecx
+ jnz .LIT
+ jmp .L1
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $1,%ecx /* ecx must be 1 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/lzo1f_d.ash b/core/lzo/lzo1f_d.ash
new file mode 100644
index 00000000..aa9279e0
--- /dev/null
+++ b/core/lzo/lzo1f_d.ash
@@ -0,0 +1,176 @@
+/* lzo1f_d.ash -- assembler implementation of the LZO1F decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+ ALIGN3
+.L0:
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ cmpb $31,%al
+ ja .LM2
+
+ orb %al,%al
+ movl %eax,%ecx
+ jnz .L2
+1:
+ LODSB
+ orb %al,%al
+ jnz 2f
+ addl N_255,%ecx
+ jmp 1b
+2:
+ lea 31(%eax,%ecx),%ecx
+.L2:
+ TEST_OP((%edi,%ecx),%ebx)
+ TEST_IP((%esi,%ecx),%ebx)
+ movb %cl,%al
+ shrl $2,%ecx
+ rep
+ movsl
+ andb $3,%al
+ jz 1f
+ movl (%esi),%ebx
+ addl %eax,%esi
+ movl %ebx,(%edi)
+ addl %eax,%edi
+1:
+ movb (%esi),%al
+ incl %esi
+.LM1:
+ cmpb $31,%al
+ jbe .LM21
+
+.LM2:
+ cmpb $223,%al
+ ja .LM3
+
+ movl %eax,%ecx
+ shrl $2,%eax
+ lea -1(%edi),%edx
+ andb $7,%al
+ shrl $5,%ecx
+ movl %eax,%ebx
+
+ movb (%esi),%al
+ leal (%ebx,%eax,8),%eax
+ incl %esi
+.LM5:
+ subl %eax,%edx
+ addl $2,%ecx
+ xchgl %edx,%esi
+ TEST_LOOKBEHIND(%esi)
+ TEST_OP((%edi,%ecx),%ebx)
+ cmpl $6,%ecx
+ jb 1f
+ cmpl $4,%eax
+ jb 1f
+ movb %cl,%al
+ shrl $2,%ecx
+ rep
+ movsl
+ andb $3,%al
+ movb %al,%cl
+1:
+ rep
+ movsb
+ movl %edx,%esi
+.LN1:
+ movb -2(%esi),%cl
+ andl $3,%ecx
+ jz .L0
+ movl (%esi),%eax
+ addl %ecx,%esi
+ movl %eax,(%edi)
+ addl %ecx,%edi
+ xorl %eax,%eax
+ movb (%esi),%al
+ incl %esi
+ jmp .LM1
+.LM21:
+ TEST_OP(3(%edi),%edx)
+ shrl $2,%eax
+ leal -0x801(%edi),%edx
+ movl %eax,%ecx
+ movb (%esi),%al
+ incl %esi
+ leal (%ecx,%eax,8),%eax
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+ movl (%edx),%eax
+ movl %eax,(%edi)
+ addl $3,%edi
+ jmp .LN1
+1:
+ LODSB
+ orb %al,%al
+ jnz 2f
+ addl N_255,%ecx
+ jmp 1b
+2:
+ lea 31(%eax,%ecx),%ecx
+ jmp .LM4
+
+ ALIGN3
+.LM3:
+ andb $31,%al
+ movl %eax,%ecx
+ jz 1b
+.LM4:
+ movl %edi,%edx
+ movw (%esi),%ax
+ addl $2,%esi
+ shrl $2,%eax
+ jnz .LM5
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $1,%ecx /* ecx must be 1 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/lzo1x_d.ash b/core/lzo/lzo1x_d.ash
new file mode 100644
index 00000000..aa138354
--- /dev/null
+++ b/core/lzo/lzo1x_d.ash
@@ -0,0 +1,401 @@
+/* lzo1x_d.ash -- assembler implementation of the LZO1X decompression algorithm
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+#if !defined(LZO1X) && !defined(LZO1Y)
+# define LZO1X
+#endif
+
+#if defined(LZO_FAST)
+# define NN 3
+#else
+# define NN 0
+#endif
+
+
+/***********************************************************************
+// init
+************************************************************************/
+
+ xorl %eax,%eax
+ xorl %ebx,%ebx /* high bits 9-32 stay 0 */
+ lodsb
+ cmpb $17,%al
+ jbe .L01
+ subb $17-NN,%al
+#if defined(LZO_FAST)
+ jmp .LFLR
+#else
+ cmpb $4,%al
+ jae .LFLR
+#if 1
+ TEST_OP((%edi,%eax),%edx)
+ TEST_IP((%esi,%eax),%edx)
+ movl %eax,%ecx
+ jmp .LFLR2
+#else
+ jmp .LFLR3
+#endif
+#endif
+
+
+/***********************************************************************
+// literal run
+************************************************************************/
+
+0: addl N_255,%eax
+ TEST_IP(18(%esi,%eax),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 18+NN(%eax,%ebx),%eax
+ jmp 3f
+
+
+ ALIGN3
+.L00:
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ TEST_IP_R(%esi)
+ LODSB
+.L01:
+ cmpb $16,%al
+ jae .LMATCH
+
+/* a literal run */
+ orb %al,%al
+ jz 1b
+ addl $3+NN,%eax
+3:
+.LFLR:
+ TEST_OP(-NN(%edi,%eax),%edx)
+ TEST_IP(-NN(%esi,%eax),%edx)
+#if defined(LZO_FAST)
+ movl %eax,%ecx
+ NOTL_3(%eax)
+ shrl $2,%ecx
+ andl N_3,%eax
+ COPYL(%esi,%edi,%edx)
+ subl %eax,%esi
+ subl %eax,%edi
+#else
+ movl %eax,%ecx
+ shrl $2,%eax
+ andl N_3,%ecx
+ COPYL_C(%esi,%edi,%edx,%eax)
+.LFLR2:
+ rep
+ movsb
+#endif
+
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ LODSB
+ cmpb $16,%al
+ jae .LMATCH
+
+
+/***********************************************************************
+// R1
+************************************************************************/
+
+ TEST_OP(3(%edi),%edx)
+ shrl $2,%eax
+ movb (%esi),%bl
+#if defined(LZO1X)
+ leal -0x801(%edi),%edx
+#elif defined(LZO1Y)
+ leal -0x401(%edi),%edx
+#endif
+ leal (%eax,%ebx,4),%eax
+ incl %esi
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+#if defined(LZO_FAST)
+ movl (%edx),%ecx
+ movl %ecx,(%edi)
+#else
+ movb (%edx),%al
+ movb %al,(%edi)
+ movb 1(%edx),%al
+ movb %al,1(%edi)
+ movb 2(%edx),%al
+ movb %al,2(%edi)
+#endif
+ addl N_3,%edi
+ jmp .LMDONE
+
+
+/***********************************************************************
+// M2
+************************************************************************/
+
+ ALIGN3
+.LMATCH:
+ cmpb $64,%al
+ jb .LM3MATCH
+
+/* a M2 match */
+ movl %eax,%ecx
+ shrl $2,%eax
+ leal -1(%edi),%edx
+#if defined(LZO1X)
+ andl $7,%eax
+ movb (%esi),%bl
+ shrl $5,%ecx
+ leal (%eax,%ebx,8),%eax
+#elif defined(LZO1Y)
+ andl N_3,%eax
+ movb (%esi),%bl
+ shrl $4,%ecx
+ leal (%eax,%ebx,4),%eax
+#endif
+ incl %esi
+ subl %eax,%edx
+
+#if defined(LZO_FAST)
+#if defined(LZO1X)
+ addl $1+3,%ecx
+#elif defined(LZO1Y)
+ addl $2,%ecx
+#endif
+#else
+#if defined(LZO1X)
+ incl %ecx
+#elif defined(LZO1Y)
+ decl %ecx
+#endif
+#endif
+
+ cmpl N_3,%eax
+ jae .LCOPYLONG
+ jmp .LCOPYBYTE
+
+
+/***********************************************************************
+// M3
+************************************************************************/
+
+0: addl N_255,%eax
+ TEST_IP(3(%esi),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 33+NN(%eax,%ebx),%ecx
+ xorl %eax,%eax
+ jmp 3f
+
+
+ ALIGN3
+.LM3MATCH:
+ cmpb $32,%al
+ jb .LM4MATCH
+
+/* a M3 match */
+ andl $31,%eax
+ jz 1b
+ lea 2+NN(%eax),%ecx
+3:
+#ifdef LZO_DEBUG
+ andl $0xffff0000,%eax ; jnz .L_assert_fail
+#endif
+ movw (%esi),%ax
+ leal -1(%edi),%edx
+ shrl $2,%eax
+ addl $2,%esi
+ subl %eax,%edx
+
+ cmpl N_3,%eax
+ jb .LCOPYBYTE
+
+
+/***********************************************************************
+// copy match
+************************************************************************/
+
+ ALIGN1
+.LCOPYLONG: /* copy match using longwords */
+ TEST_LOOKBEHIND(%edx)
+#if defined(LZO_FAST)
+ leal -3(%edi,%ecx),%eax
+ shrl $2,%ecx
+ TEST_OP_R(%eax)
+ COPYL(%edx,%edi,%ebx)
+ movl %eax,%edi
+ xorl %ebx,%ebx
+#else
+ TEST_OP((%edi,%ecx),%eax)
+ movl %ecx,%ebx
+ shrl $2,%ebx
+ jz 2f
+ COPYL_C(%edx,%edi,%eax,%ebx)
+ andl N_3,%ecx
+ jz 1f
+2: COPYB_C(%edx,%edi,%al,%ecx)
+1:
+#endif
+
+.LMDONE:
+ movb -2(%esi),%al
+ andl N_3,%eax
+ jz .L00
+.LFLR3:
+ TEST_OP((%edi,%eax),%edx)
+ TEST_IP((%esi,%eax),%edx)
+#if defined(LZO_FAST)
+ movl (%esi),%edx
+ addl %eax,%esi
+ movl %edx,(%edi)
+ addl %eax,%edi
+#else
+ COPYB_C(%esi,%edi,%cl,%eax)
+#endif
+
+#ifdef LZO_DEBUG
+ andl $0xffffff00,%eax ; jnz .L_assert_fail
+ andl $0xffffff00,%ebx ; jnz .L_assert_fail
+ xorl %eax,%eax ; xorl %ebx,%ebx
+ xorl %ecx,%ecx ; xorl %edx,%edx
+#endif
+ LODSB
+ jmp .LMATCH
+
+
+ ALIGN3
+.LCOPYBYTE: /* copy match using bytes */
+ TEST_LOOKBEHIND(%edx)
+ TEST_OP(-NN(%edi,%ecx),%eax)
+ xchgl %edx,%esi
+#if defined(LZO_FAST)
+ subl N_3,%ecx
+#endif
+ rep
+ movsb
+ movl %edx,%esi
+ jmp .LMDONE
+
+
+/***********************************************************************
+// M4
+************************************************************************/
+
+0: addl N_255,%ecx
+ TEST_IP(3(%esi),%edx) /* minimum */
+1: movb (%esi),%bl
+ incl %esi
+ orb %bl,%bl
+ jz 0b
+ leal 9+NN(%ebx,%ecx),%ecx
+ jmp 3f
+
+
+ ALIGN3
+.LM4MATCH:
+ cmpb $16,%al
+ jb .LM1MATCH
+
+/* a M4 match */
+ movl %eax,%ecx
+ andl $8,%eax
+ shll $13,%eax /* save in bit 16 */
+ andl $7,%ecx
+ jz 1b
+ addl $2+NN,%ecx
+3:
+#ifdef LZO_DEBUG
+ movl %eax,%edx ; andl $0xfffe0000,%edx ; jnz .L_assert_fail
+#endif
+ movw (%esi),%ax
+ addl $2,%esi
+ leal -0x4000(%edi),%edx
+ shrl $2,%eax
+ jz .LEOF
+ subl %eax,%edx
+ jmp .LCOPYLONG
+
+
+/***********************************************************************
+// M1
+************************************************************************/
+
+ ALIGN3
+.LM1MATCH:
+/* a M1 match */
+ TEST_OP(2(%edi),%edx)
+ shrl $2,%eax
+ movb (%esi),%bl
+ leal -1(%edi),%edx
+ leal (%eax,%ebx,4),%eax
+ incl %esi
+ subl %eax,%edx
+ TEST_LOOKBEHIND(%edx)
+
+ movb (%edx),%al /* we must use this because edx can be edi-1 */
+ movb %al,(%edi)
+ movb 1(%edx),%bl
+ movb %bl,1(%edi)
+ addl $2,%edi
+ jmp .LMDONE
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+.LEOF:
+/**** xorl %eax,%eax eax=0 from above */
+
+ cmpl $3+NN,%ecx /* ecx must be 3/6 */
+ setnz %al
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/lzo1x_f1.S b/core/lzo/lzo1x_f1.S
new file mode 100644
index 00000000..8360e34a
--- /dev/null
+++ b/core/lzo/lzo1x_f1.S
@@ -0,0 +1,63 @@
+/* lzo1x_f1.S -- fast LZO1X decompression in assembler (i386 + gcc)
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define LZO_FAST
+
+#include "lzo_asm.h"
+
+ .section ".textnr","ax"
+
+ LZO_PUBLIC(lzo1x_decompress_asm_fast)
+
+#include "enter.ash"
+#include "lzo1x_d.ash"
+#include "leave.ash"
+
+ LZO_PUBLIC_END(lzo1x_decompress_asm_fast)
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/lzo/lzo_asm.h b/core/lzo/lzo_asm.h
new file mode 100644
index 00000000..55fdf6d1
--- /dev/null
+++ b/core/lzo/lzo_asm.h
@@ -0,0 +1,287 @@
+/* lzo_asm.h -- LZO assembler stuff
+
+ This file is part of the LZO real-time data compression library.
+
+ Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+ Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+ All Rights Reserved.
+
+ The LZO library 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; either version 2 of
+ the License, or (at your option) any later version.
+
+ The LZO library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with the LZO library; see the file COPYING.
+ If not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ Markus F.X.J. Oberhumer
+ <markus@oberhumer.com>
+ http://www.oberhumer.com/opensource/lzo/
+ */
+
+
+/***********************************************************************
+// <asmconfig.h>
+************************************************************************/
+
+#if !defined(__i386__)
+# error
+#endif
+
+#if !defined(IN_CONFIGURE)
+#if defined(LZO_HAVE_CONFIG_H)
+# include <config.h>
+#else
+ /* manual configuration - see defaults below */
+# if defined(__ELF__)
+# define MFX_ASM_HAVE_TYPE
+# define MFX_ASM_NAME_NO_UNDERSCORES
+# elif defined(__linux__) /* Linux a.out */
+# define MFX_ASM_ALIGN_PTWO
+# elif defined(__DJGPP__)
+# define MFX_ASM_ALIGN_PTWO
+# elif defined(__GO32__) /* djgpp v1 */
+# define MFX_ASM_CANNOT_USE_EBP
+# elif defined(__EMX__)
+# define MFX_ASM_ALIGN_PTWO
+# define MFX_ASM_CANNOT_USE_EBP
+# endif
+#endif
+#endif
+
+#if 1 && defined(__ELF__)
+.section .note.GNU-stack,"",@progbits
+#endif
+#if 0 && defined(__ELF__)
+#undef i386
+.arch i386
+.code32
+#endif
+
+
+/***********************************************************************
+// name always uses underscores
+// [ OLD: name (default: with underscores) ]
+************************************************************************/
+
+#if !defined(LZO_ASM_NAME)
+# define LZO_ASM_NAME(n) _ ## n
+#if 0
+# if defined(MFX_ASM_NAME_NO_UNDERSCORES)
+# define LZO_ASM_NAME(n) n
+# else
+# define LZO_ASM_NAME(n) _ ## n
+# endif
+#endif
+#endif
+
+
+/***********************************************************************
+// .type (default: do not use)
+************************************************************************/
+
+#if !defined(LZO_PUBLIC)
+#if defined(__LZO_DB__)
+# define LZO_PUBLIC(func) \
+ .p2align 4 ; .byte 0,0,0,0,0,0,0 ; .ascii "LZO_START"
+# define LZO_PUBLIC_END(func) \
+ .p2align 4,0x90 ; .ascii "LZO_END"
+#elif defined(MFX_ASM_HAVE_TYPE)
+# define LZO_PUBLIC(func) \
+ ALIGN3 ; .type LZO_ASM_NAME(func),@function ; \
+ .globl LZO_ASM_NAME(func) ; LZO_ASM_NAME(func):
+# define LZO_PUBLIC_END(func) \
+ .size LZO_ASM_NAME(func),.-LZO_ASM_NAME(func)
+#else
+# define LZO_PUBLIC(func) \
+ ALIGN3 ; .globl LZO_ASM_NAME(func) ; LZO_ASM_NAME(func):
+# define LZO_PUBLIC_END(func)
+#endif
+#endif
+
+
+/***********************************************************************
+// .align (default: bytes)
+************************************************************************/
+
+#if !defined(MFX_ASM_ALIGN_BYTES) && !defined(MFX_ASM_ALIGN_PTWO)
+# define MFX_ASM_ALIGN_BYTES
+#endif
+
+#if !defined(LZO_ASM_ALIGN)
+# if defined(MFX_ASM_ALIGN_PTWO)
+# define LZO_ASM_ALIGN(x) .align x
+# else
+# define LZO_ASM_ALIGN(x) .align (1 << (x))
+# endif
+#endif
+
+#define ALIGN1 LZO_ASM_ALIGN(1)
+#define ALIGN2 LZO_ASM_ALIGN(2)
+#define ALIGN3 LZO_ASM_ALIGN(3)
+
+
+/***********************************************************************
+// ebp usage (default: can use)
+************************************************************************/
+
+#if !defined(MFX_ASM_CANNOT_USE_EBP)
+# if 1 && !defined(N_3_EBP) && !defined(N_255_EBP)
+# define N_3_EBP
+# endif
+# if 0 && !defined(N_3_EBP) && !defined(N_255_EBP)
+# define N_255_EBP
+# endif
+#endif
+
+#if defined(N_3_EBP) && defined(N_255_EBP)
+# error
+#endif
+#if defined(MFX_ASM_CANNOT_USE_EBP)
+# if defined(N_3_EBP) || defined(N_255_EBP)
+# error
+# endif
+#endif
+
+#if !defined(N_3)
+# if defined(N_3_EBP)
+# define N_3 %ebp
+# else
+# define N_3 $3
+# endif
+#endif
+
+#if !defined(N_255)
+# if defined(N_255_EBP)
+# define N_255 %ebp
+# define NOTL_3(r) xorl %ebp,r
+# else
+# define N_255 $255
+# endif
+#endif
+
+#if !defined(NOTL_3)
+# define NOTL_3(r) xorl N_3,r
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#ifndef INP
+#define INP 4+36(%esp)
+#define INS 8+36(%esp)
+#define OUTP 12+36(%esp)
+#define OUTS 16+36(%esp)
+#endif
+
+#define INEND 4(%esp)
+#define OUTEND (%esp)
+
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_INPUT)
+# define TEST_IP_R(r) cmpl r,INEND ; jb .L_input_overrun
+# define TEST_IP(addr,r) leal addr,r ; TEST_IP_R(r)
+#else
+# define TEST_IP_R(r)
+# define TEST_IP(addr,r)
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_OUTPUT)
+# define TEST_OP_R(r) cmpl r,OUTEND ; jb .L_output_overrun
+# define TEST_OP(addr,r) leal addr,r ; TEST_OP_R(r)
+#else
+# define TEST_OP_R(r)
+# define TEST_OP(addr,r)
+#endif
+
+#if defined(LZO_TEST_DECOMPRESS_OVERRUN_LOOKBEHIND)
+# define TEST_LOOKBEHIND(r) cmpl OUTP,r ; jb .L_lookbehind_overrun
+#else
+# define TEST_LOOKBEHIND(r)
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+
+#define LODSB movb (%esi),%al ; incl %esi
+
+#define MOVSB(r1,r2,x) movb (r1),x ; incl r1 ; movb x,(r2) ; incl r2
+#define MOVSW(r1,r2,x) movb (r1),x ; movb x,(r2) ; \
+ movb 1(r1),x ; addl $2,r1 ; \
+ movb x,1(r2) ; addl $2,r2
+#define MOVSL(r1,r2,x) movl (r1),x ; addl $4,r1 ; movl x,(r2) ; addl $4,r2
+
+#if defined(LZO_DEBUG)
+#define COPYB_C(r1,r2,x,rc) \
+ cmpl $0,rc ; jz .L_assert_fail; \
+ 9: MOVSB(r1,r2,x) ; decl rc ; jnz 9b
+#define COPYL_C(r1,r2,x,rc) \
+ cmpl $0,rc ; jz .L_assert_fail; \
+ 9: MOVSL(r1,r2,x) ; decl rc ; jnz 9b
+#else
+#define COPYB_C(r1,r2,x,rc) \
+ 9: MOVSB(r1,r2,x) ; decl rc ; jnz 9b
+#define COPYL_C(r1,r2,x,rc) \
+ 9: MOVSL(r1,r2,x) ; decl rc ; jnz 9b
+#endif
+
+#define COPYB(r1,r2,x) COPYB_C(r1,r2,x,%ecx)
+#define COPYL(r1,r2,x) COPYL_C(r1,r2,x,%ecx)
+
+
+/***********************************************************************
+// not used
+************************************************************************/
+
+#if 0
+
+#if 0
+#define REP_MOVSB(x) rep ; movsb
+#define REP_MOVSL(x) shrl $2,%ecx ; rep ; movsl
+#elif 1
+#define REP_MOVSB(x) COPYB(%esi,%edi,x)
+#define REP_MOVSL(x) shrl $2,%ecx ; COPYL(%esi,%edi,x)
+#else
+#define REP_MOVSB(x) rep ; movsb
+#define REP_MOVSL(x) jmp 9f ; 8: movsb ; decl %ecx ; \
+ 9: testl $3,%edi ; jnz 8b ; \
+ movl %ecx,x ; shrl $2,%ecx ; andl $3,x ; \
+ rep ; movsl ; movl x,%ecx ; rep ; movsb
+#endif
+
+#if 1
+#define NEGL(x) negl x
+#else
+#define NEGL(x) xorl $-1,x ; incl x
+#endif
+
+#endif
+
+
+
+/*
+vi:ts=4
+*/
+
diff --git a/core/macros.inc b/core/macros.inc
index 1aa2b2ce..e3aedca1 100644
--- a/core/macros.inc
+++ b/core/macros.inc
@@ -47,7 +47,7 @@
;
; Macros similar to res[bwd], but which works in the code segment (after
-; section .text) or the data segment (section .data)
+; section .text16) or the data segment (section .data16)
;
%macro zb 1.nolist
times %1 db 0
diff --git a/core/malloc.c b/core/malloc.c
new file mode 100644
index 00000000..a033ff03
--- /dev/null
+++ b/core/malloc.c
@@ -0,0 +1,216 @@
+/*
+ * A simple temp malloc for Sysliux project from fstk. For now, just used
+ * in fsc branch, which it's would be easy to remove it when we have a
+ * powerful one, as hpa said this would happen when elflink branch do the
+ * work.
+ *
+ * Copyright (C) 2009 Liu Aleaxander -- All rights reserved. This file
+ * may be redistributed under the terms of the GNU Public License.
+ */
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+
+/* The memory managemant structure */
+struct mem_struct {
+ struct mem_struct *prev;
+ int size;
+ int free;
+};
+
+
+/* First, assume we just need 64K memory */
+static char memory[0x10000];
+
+/* Next free memory address */
+static struct mem_struct *next_start = (struct mem_struct *)memory;
+static uint32_t mem_end = (uint32_t)(memory + 0x10000);
+
+
+static inline struct mem_struct *get_next(struct mem_struct *mm)
+{
+ uint32_t next = (uint32_t)mm + mm->size;
+
+ if (next >= mem_end)
+ return NULL;
+ else
+ return (struct mem_struct *)next;
+}
+
+/*
+ * Here are the _merge_ functions, that merges a adjacent memory region,
+ * from front, or from back, or even merges both. It returns the headest
+ * region mem_struct.
+ *
+ */
+
+static struct mem_struct * merge_front(struct mem_struct *mm,
+ struct mem_struct *prev)
+{
+ struct mem_struct *next = get_next(mm);
+
+ prev->size += mm->size;
+ if (next)
+ next->prev = prev;
+ return prev;
+}
+
+static struct mem_struct * merge_back(struct mem_struct *mm,
+ struct mem_struct *next)
+{
+ mm->free = 1; /* Mark it free first */
+ mm->size += next->size;
+
+ next = get_next(next);
+ if (next)
+ next->prev = mm;
+ return mm;
+}
+
+static struct mem_struct * merge_both(struct mem_struct *mm,
+ struct mem_struct *prev,
+ struct mem_struct *next)
+{
+ prev->size += mm->size + next->size;
+
+ next = get_next(next);
+ if (next)
+ next->prev = prev;
+ return prev;
+}
+
+static inline struct mem_struct * try_merge_front(struct mem_struct *mm)
+{
+ mm->free = 1;
+ if (mm->prev->free)
+ mm = merge_front(mm, mm->prev);
+ return mm;
+}
+
+static inline struct mem_struct * try_merge_back(struct mem_struct *mm)
+{
+ struct mem_struct *next = get_next(mm);
+
+ mm->free = 1;
+ if (next->free)
+ merge_back(mm, next);
+ return mm;
+}
+
+/*
+ * Here's the main function, malloc, which allocates a memory rigon
+ * of size _size_. Returns NULL if failed, or the address newly allocated.
+ *
+ */
+void *malloc(int size)
+{
+ struct mem_struct *next = next_start;
+ struct mem_struct *good = next, *prev;
+ int size_needed = (size + sizeof(struct mem_struct) + 3) & ~3;
+
+ while(next) {
+ if (next->free && next->size >= size_needed) {
+ good = next;
+ break;
+ }
+ next = get_next(next);
+ }
+ if (good->size < size_needed) {
+ printf("Out of memory, maybe we need append it\n");
+ return NULL;
+ } else if (good->size == size_needed) {
+ /*
+ * We just found a right memory that with the exact
+ * size we want. So we just Mark it _not_free_ here,
+ * and move on the _next_start_ pointer, even though
+ * the next may not be a right next start.
+ */
+ good->free = 0;
+ next_start = get_next(good);
+ goto out;
+ } else
+ size = good->size; /* save the total size */
+
+ /*
+ * Note: allocate a new memory region will not change
+ * it's prev memory, so we don't need change it here.
+ */
+ good->free = 0; /* Mark it not free any more */
+ good->size = size_needed;
+
+ next = get_next(good);
+ if (next) {
+ next->size = size - size_needed;
+ /* check if it can contain 1 byte allocation at least */
+ if (next->size <= (int)sizeof(struct mem_struct)) {
+ good->size = size; /* restore the original size */
+ next_start = get_next(good);
+ goto out;
+ }
+
+ next->prev = good;
+ next->free = 1;
+ next_start = next; /* Update next_start */
+
+ prev = next;
+ next = get_next(next);
+ if (next)
+ next->prev = prev;
+ } else
+ next_start = (struct mem_struct *)memory;
+out:
+ return (void *)((uint32_t)good + sizeof(struct mem_struct));
+}
+
+void free(void *ptr)
+{
+ struct mem_struct *mm = ptr - sizeof(*mm);
+ struct mem_struct *prev = mm->prev;
+ struct mem_struct *next = get_next(mm);
+
+ if (!prev)
+ mm = try_merge_back(mm);
+ else if (!next)
+ mm = try_merge_front(mm);
+ else if (prev->free && !next->free)
+ merge_front(mm, prev);
+ else if (!prev->free && next->free)
+ merge_back(mm, next);
+ else if (prev->free && next->free)
+ merge_both(mm, prev, next);
+ else
+ mm->free = 1;
+
+ if (mm < next_start)
+ next_start = mm;
+}
+
+/*
+ * The debug function
+ */
+void check_mem(void)
+{
+ struct mem_struct *next = (struct mem_struct *)memory;
+
+ printf("____________\n");
+ while (next) {
+ printf("%-6d %s\n", next->size, next->free ? "Free" : "Notf");
+ next = get_next(next);
+ }
+ printf("\n");
+}
+
+
+void mem_init(void)
+{
+
+ struct mem_struct *first = (struct mem_struct *)memory;
+
+ first->prev = NULL;
+ first->size = 0x10000;
+ first->free = 1;
+
+ next_start = first;
+}
diff --git a/core/parsecmd.inc b/core/parsecmd.inc
index 1ddd5a0e..ab5a7df9 100644
--- a/core/parsecmd.inc
+++ b/core/parsecmd.inc
@@ -17,7 +17,7 @@
;; Command line parser code
;;
- section .text
+ section .text16
; -------------------------------------------------------------------------
; getcommand: Get a keyword from the current "getc" file and match it
@@ -106,11 +106,12 @@ skipline: cmp al,10 ; Search for LF
jnc skipline
.end: ret
- section .data
+ section .data16
err_badcfg db 'Unknown keyword in configuration file: ',0
err_noparm db 'Missing parameter in configuration file. Keyword: ',0
section .uibss
+ global KernelName
alignb 4
vk_size equ (vk_end + 3) & ~3
VKernelBuf: resb vk_size ; "Current" vkernel
@@ -118,7 +119,7 @@ AppendBuf resb max_cmd_len+1 ; append=
Ontimeout resb max_cmd_len+1 ; ontimeout
Onerror resb max_cmd_len+1 ; onerror
; This could be in .uibss but that makes PXELINUX overflow
- section .bss
+ section .bss16
KbdMap resb 256 ; Keyboard map
FKeyName resb MAX_FKEYS*FILENAME_MAX ; File names for F-key help
KernelCNameLen resw 1 ; Length of unmangled kernel name
@@ -134,3 +135,5 @@ InitRDCName resb FILENAME_MAX ; Unmangled initrd name
%endif
MNameBuf resb FILENAME_MAX
InitRD resb FILENAME_MAX
+
+ section .text16
diff --git a/core/parseconfig.inc b/core/parseconfig.inc
index 65d71c95..af7d514f 100644
--- a/core/parseconfig.inc
+++ b/core/parseconfig.inc
@@ -17,7 +17,7 @@
;; Configuration file operations
;;
- section .text
+ section .text16
;
; "default" or "ui" command, with level (1 = default, 2 = ui)
;
@@ -104,7 +104,7 @@ pc_kernel: cmp byte [VKernel],0
mov [VKernelBuf+vk_type],al
call pc_getline
mov di,VKernelBuf+vk_rname
- call mangle_name
+ pm_call mangle_name
.err: ret
;
@@ -147,8 +147,8 @@ pc_setint16:
pc_filecmd: push ax ; Function to tailcall
call pc_getline
mov di,MNameBuf
- call mangle_name
- call searchdir
+ pm_call mangle_name
+ pm_call searchdir
jnz .ok
pop ax ; Drop the successor function
.ok: ret ; Tailcall if OK, error return
@@ -160,8 +160,8 @@ pc_filecmd: push ax ; Function to tailcall
pc_opencmd: push ax ; Function to tailcall
call pc_getline
mov di,MNameBuf
- call mangle_name
- call open
+ pm_call mangle_name
+ call core_open
jnz .ok
pop ax ; Drop the successor function
.ok: ret ; Tailcall if OK, error return
@@ -289,7 +289,7 @@ pc_serial: call getint
pc_filename: push ax
call pc_getline
pop di
- call mangle_name ; Mangle file name
+ pm_call mangle_name ; Mangle file name
ret
;
@@ -314,7 +314,7 @@ pc_label: call commit_vk ; Commit any current vkernel
mov byte [VKernel],1 ; We've seen a "label" statement
mov si,VKernelBuf+vk_vname ; By default, rname == mangled vname
mov di,VKernelBuf+vk_rname
- call mangle_name
+ pm_call mangle_name
mov si,AppendBuf ; Default append==global append
mov di,VKernelBuf+vk_append
mov cx,[AppendLen]
@@ -409,7 +409,7 @@ commit_vk:
mov cx,7 ; "initrd="
rep movsb
mov si,InitRD
- call unmangle_name
+ pm_call unmangle_name
mov al,' '
stosb
@@ -427,7 +427,7 @@ commit_vk:
mov esi,VKernelBuf
mov edi,[VKernelEnd]
mov ecx,vk_size
- call rllpack
+ pm_call rllpack
mov [VKernelEnd],edi
.nolabel:
ret
@@ -436,11 +436,11 @@ commit_vk:
call writestr
ret
- section .data
+ section .data16
vk_overflow_msg db 'Out of memory parsing config file', CR, LF, 0
SerialNotice db 1 ; Only print this once
- section .bss
+ section .bss16
alignb 4
VKernelEnd resd 1 ; Lowest high memory address used
@@ -474,5 +474,3 @@ IPAppend db 0 ; Default IPAPPEND option
command_line resb max_cmd_len+2 ; Command line buffer
alignb 4
default_cmd resb max_cmd_len+1 ; "default" command line
-
-%include "rllpack.inc"
diff --git a/core/plaincon.inc b/core/plaincon.inc
index 59b2cbb5..c41629d0 100644
--- a/core/plaincon.inc
+++ b/core/plaincon.inc
@@ -2,7 +2,7 @@
; writechr: Write a single character in AL to the console without
; mangling any registers; handle video pages correctly.
;
- section .text
+ section .text16
writechr:
call write_serial ; write to serial port if needed
diff --git a/core/pm.inc b/core/pm.inc
new file mode 100644
index 00000000..9584cda1
--- /dev/null
+++ b/core/pm.inc
@@ -0,0 +1,450 @@
+;; -----------------------------------------------------------------------
+;;
+;; Copyright 1994-2009 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
+;; 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.
+;;
+;; -----------------------------------------------------------------------
+
+;;
+;; pm.inc
+;;
+;; Functions to enter and exit 32-bit protected mode, handle interrupts
+;; and cross-mode calls.
+;;
+;; PM refers to 32-bit flat protected mode; RM to 16-bit real mode.
+;;
+
+ bits 16
+ section .text16
+;
+; _pm_call: call PM routine in low memory from RM
+;
+; on stack = PM routine to call (a 32-bit address)
+;
+; ECX, ESI, EDI passed to the called function;
+; EAX = EBP in the called function points to the stack frame
+; which includes all registers (which can be changed if desired.)
+;
+; All registers and the flags saved/restored
+;
+; This routine is invoked by the pm_call macro.
+;
+_pm_call:
+ pushfd
+ pushad
+ push ds
+ push es
+ push fs
+ push gs
+ mov bp,sp
+ mov ax,cs
+ mov ebx,.pm
+ mov ds,ax
+ jmp enter_pm
+
+ bits 32
+ section .textnr
+.pm:
+ ; EAX points to the top of the RM stack, which is EFLAGS
+ test RM_FLAGSH,02h ; RM EFLAGS.IF
+ jz .no_sti
+ sti
+.no_sti:
+ call [ebp+4*2+9*4+2] ; Entrypoint on RM stack
+ mov bx,.rm
+ jmp enter_rm
+
+ bits 16
+ section .text16
+.rm:
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ popad
+ popfd
+ ret 4 ; Drop entrypoint
+
+;
+; enter_pm: Go to PM with interrupt service configured
+; EBX = PM entry point
+; EAX = EBP = on exit, points to the RM stack as a 32-bit value
+; ECX, EDX, ESI, EDI preserved across this routine
+;
+; Assumes CS == DS
+;
+; This routine doesn't enable interrupts, but the target routine
+; can enable interrupts by executing STI.
+;
+ bits 16
+ section .text16
+enter_pm:
+ cli
+ xor eax,eax
+ mov ds,ax
+ mov ax,ss
+ mov [RealModeSSSP],sp
+ mov [RealModeSSSP+2],ax
+ movzx ebp,sp
+ shl eax,4
+ add ebp,eax ; EBP -> top of real-mode stack
+ cld
+ call enable_a20
+
+.a20ok:
+ mov byte [bcopy_gdt.TSS+5],89h ; Mark TSS unbusy
+
+ lgdt [bcopy_gdt] ; We can use the same GDT just fine
+ lidt [PM_IDT_ptr] ; Set up the IDT
+ mov eax,cr0
+ or al,1
+ mov cr0,eax ; Enter protected mode
+ jmp PM_CS32:.in_pm
+
+ bits 32
+ section .textnr
+.in_pm:
+ xor eax,eax ; Available for future use...
+ mov fs,eax
+ mov gs,eax
+ lldt ax
+
+ mov al,PM_DS32 ; Set up data segments
+ mov es,eax
+ mov ds,eax
+ mov ss,eax
+
+ mov al,PM_TSS ; Be nice to Intel's VT by
+ ltr ax ; giving it a valid TR
+
+ mov esp,[PMESP] ; Load protmode %esp
+ mov eax,ebp ; EAX -> top of real-mode stack
+ jmp ebx ; Go to where we need to go
+
+;
+; enter_rm: Return to RM from PM
+;
+; BX = RM entry point (CS = 0)
+; ECX, EDX, ESI, EDI preserved across this routine
+; EAX clobbered
+; EBP reserved
+;
+; This routine doesn't enable interrupts, but the target routine
+; can enable interrupts by executing STI.
+;
+ bits 32
+ section .textnr
+enter_rm:
+ cli
+ cld
+ mov [PMESP],esp ; Save exit %esp
+ jmp PM_CS16:.in_pm16 ; Return to 16-bit mode first
+
+ bits 16
+ section .text16
+.in_pm16:
+ mov ax,PM_DS16 ; Real-mode-like segment
+ mov es,ax
+ mov ds,ax
+ mov ss,ax
+ mov fs,ax
+ mov gs,ax
+
+ lidt [RM_IDT_ptr] ; Real-mode IDT (rm needs no GDT)
+ xor dx,dx
+ mov eax,cr0
+ and al,~1
+ mov cr0,eax
+ jmp 0:.in_rm
+
+.in_rm: ; Back in real mode
+ lss sp,[cs:RealModeSSSP] ; Restore stack
+ movzx esp,sp ; Make sure the high bits are zero
+ mov ds,dx ; Set up sane segments
+ mov es,dx
+ mov fs,dx
+ mov gs,dx
+ jmp bx ; Go to whereever we need to go...
+
+ section .data16
+ alignz 4
+
+ extern __stack_end
+PMESP dd __stack_end ; Protected-mode ESP
+
+PM_IDT_ptr: dw 8*256-1 ; Length
+ dd IDT ; Offset
+
+;
+; This is invoked on getting an interrupt in protected mode. At
+; this point, we need to context-switch to real mode and invoke
+; the interrupt routine.
+;
+; When this gets invoked, the registers are saved on the stack and
+; AL contains the register number.
+;
+ bits 32
+ section .textnr
+pm_irq:
+ pushad
+ movzx esi,byte [esp+8*4] ; Interrupt number
+ mov ebx,.rm
+ jmp enter_rm ; Go to real mode
+
+ bits 16
+ section .text16
+.rm:
+ pushf ; Flags on stack
+ call far [cs:esi*4] ; Call IVT entry
+ mov ebx,.pm
+ jmp enter_pm ; Go back to PM
+
+ bits 32
+ section .textnr
+.pm:
+ popad
+ add esp,4 ; Drop interrupt number
+ iretd
+
+ bits 16
+ section .text16
+;
+; Routines to enable and disable (yuck) A20. These routines are gathered
+; from tips from a couple of sources, including the Linux kernel and
+; http://www.x86.org/. The need for the delay to be as large as given here
+; is indicated by Donnie Barnes of RedHat, the problematic system being an
+; IBM ThinkPad 760EL.
+;
+
+ section .data16
+ alignz 2
+A20Ptr dw a20_dunno
+
+ section .bss16
+ alignb 4
+A20Test resd 1 ; Counter for testing A20 status
+A20Tries resb 1 ; Times until giving up on A20
+
+ section .text16
+enable_a20:
+ pushad
+ mov byte [cs:A20Tries],255 ; Times to try to make this work
+
+try_enable_a20:
+
+;
+; First, see if we are on a system with no A20 gate, or the A20 gate
+; is already enabled for us...
+;
+a20_none:
+ call a20_test
+ jnz a20_done
+ ; Otherwise, see if we had something memorized...
+ jmp word [cs:A20Ptr]
+
+;
+; Next, try the BIOS (INT 15h AX=2401h)
+;
+a20_dunno:
+a20_bios:
+ mov word [cs:A20Ptr], a20_bios
+ mov ax,2401h
+ pushf ; Some BIOSes muck with IF
+ int 15h
+ popf
+
+ call a20_test
+ jnz a20_done
+
+;
+; Enable the keyboard controller A20 gate
+;
+a20_kbc:
+ mov dl, 1 ; Allow early exit
+ call empty_8042
+ jnz a20_done ; A20 live, no need to use KBC
+
+ mov word [cs:A20Ptr], a20_kbc ; Starting KBC command sequence
+
+ mov al,0D1h ; Write output port
+ out 064h, al
+ call empty_8042_uncond
+
+ mov al,0DFh ; A20 on
+ out 060h, al
+ call empty_8042_uncond
+
+ ; Apparently the UHCI spec assumes that A20 toggle
+ ; ends with a null command (assumed to be for sychronization?)
+ ; Put it here to see if it helps anything...
+ mov al,0FFh ; Null command
+ out 064h, al
+ call empty_8042_uncond
+
+ ; Verify that A20 actually is enabled. Do that by
+ ; observing a word in low memory and the same word in
+ ; the HMA until they are no longer coherent. Note that
+ ; we don't do the same check in the disable case, because
+ ; we don't want to *require* A20 masking (SYSLINUX should
+ ; work fine without it, if the BIOS does.)
+.kbc_wait: push cx
+ xor cx,cx
+.kbc_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .kbc_wait_loop
+
+ pop cx
+;
+; Running out of options here. Final attempt: enable the "fast A20 gate"
+;
+a20_fast:
+ mov word [cs:A20Ptr], a20_fast
+ in al, 092h
+ or al,02h
+ and al,~01h ; Don't accidentally reset the machine!
+ out 092h, al
+
+.fast_wait: push cx
+ xor cx,cx
+.fast_wait_loop:
+ call a20_test
+ jnz a20_done_pop
+ loop .fast_wait_loop
+
+ pop cx
+
+;
+; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up
+; and report failure to the user.
+;
+ dec byte [cs:A20Tries]
+ jnz a20_dunno ; Did we get the wrong type?
+
+ mov si, err_a20
+ jmp abort_load
+
+ section .data16
+err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
+ section .text16
+
+;
+; A20 unmasked, proceed...
+;
+a20_done_pop: pop cx
+a20_done: popad
+ ret
+
+;
+; This routine tests if A20 is enabled (ZF = 0). This routine
+; must not destroy any register contents.
+;
+; The no-write early out avoids the io_delay in the (presumably common)
+; case of A20 already enabled (e.g. from a previous call.)
+;
+a20_test:
+ push es
+ push cx
+ push eax
+ mov cx,0FFFFh ; HMA = segment 0FFFFh
+ mov es,cx
+ mov eax,[cs:A20Test]
+ mov cx,32 ; Loop count
+ jmp .test ; First iteration = early out
+.wait: add eax,0x430aea41 ; A large prime number
+ mov [cs:A20Test],eax
+ io_delay ; Serialize, and fix delay
+.test: cmp eax,[es:A20Test+10h]
+ loopz .wait
+.done: pop eax
+ pop cx
+ pop es
+ ret
+
+;
+; Routine to empty the 8042 KBC controller. If dl != 0
+; then we will test A20 in the loop and exit if A20 is
+; suddenly enabled.
+;
+empty_8042_uncond:
+ xor dl,dl
+empty_8042:
+ call a20_test
+ jz .a20_on
+ and dl,dl
+ jnz .done
+.a20_on: io_delay
+ in al, 064h ; Status port
+ test al,1
+ jz .no_output
+ io_delay
+ in al, 060h ; Read input
+ jmp short empty_8042
+.no_output:
+ test al,2
+ jnz empty_8042
+ io_delay
+.done: ret
+
+;
+; This initializes the protected-mode interrupt thunk set
+;
+ section .text16
+pm_init:
+ xor edi,edi
+ mov bx,IDT
+ mov di,IRQStubs
+
+ mov eax,7aeb006ah ; push byte .. jmp short ..
+
+ mov cx,8 ; 8 groups of 32 IRQs
+.gloop:
+ push cx
+ mov cx,32 ; 32 entries per group
+.eloop:
+ mov [bx],di ; IDT offset [15:0]
+ mov word [bx+2],PM_CS32 ; IDT segment
+ mov dword [bx+4],08e00h ; IDT offset [31:16], 32-bit interrupt
+ ; gate, CPL 0 (we don't have a TSS
+ ; set up...)
+ add bx,8
+
+ stosd
+ ; Increment IRQ, decrement jmp short offset
+ add eax,(-4 << 24)+(1 << 8)
+
+ loop .eloop
+
+ ; At the end of each group, replace the EBxx with
+ ; the final E9xxxxxxxx
+ add di,3
+ mov byte [di-5],0E9h ; JMP NEAR
+ mov edx,pm_irq
+ sub edx,edi
+ mov [di-4],edx
+
+ add eax,(0x80 << 24) ; Proper offset for the next one
+ pop cx
+ loop .gloop
+
+ ret
+
+ ; pm_init is called before bss clearing, so put these
+ ; in .earlybss!
+ section .earlybss
+ alignb 8
+IDT: resq 256
+RealModeSSSP resd 1 ; Real-mode SS:SP
+
+ section .gentextnr ; Autogenerated 32-bit code
+IRQStubs: resb 4*256+3*8
+
+ section .text16
+
+%include "callback.inc" ; Real-mode callbacks
diff --git a/core/pmcall.inc b/core/pmcall.inc
new file mode 100644
index 00000000..0a580150
--- /dev/null
+++ b/core/pmcall.inc
@@ -0,0 +1,70 @@
+;;
+;; pmcall.inc
+;;
+;; Macros for the stack frame set up by pm_call, assuming ebp is left
+;; as the RM frame pointer.
+;;
+
+%ifndef PMCALL_INC
+%define PMCALL_INC
+
+%define RM_GS word [ebp]
+%define RM_FS word [ebp+2]
+%define RM_ES word [ebp+4]
+%define RM_DS word [ebp+6]
+
+%define RM_EDI dword [ebp+8]
+%define RM_DI word [ebp+8]
+%define RM_HDI word [ebp+10]
+%define RM_DIL byte [ebp+8]
+%define RM_DIH byte [ebp+9]
+
+%define RM_ESI dword [ebp+12]
+%define RM_SI word [ebp+12]
+%define RM_HSI word [ebp+14]
+%define RM_SIL byte [ebp+12]
+%define RM_SIH byte [ebp+13]
+
+%define RM_EBP dword [ebp+16]
+%define RM_BP word [ebp+16]
+%define RM_HBP word [ebp+18]
+%define RM_BPL byte [ebp+16]
+%define RM_BPH byte [ebp+17]
+
+%define RM_EBX dword [ebp+24]
+%define RM_BX word [ebp+24]
+%define RM_HBX word [ebp+26]
+%define RM_BL byte [ebp+24]
+%define RM_BH byte [ebp+25]
+
+%define RM_EDX dword [ebp+28]
+%define RM_DX word [ebp+28]
+%define RM_HDX word [ebp+30]
+%define RM_DL byte [ebp+28]
+%define RM_DH byte [ebp+29]
+
+%define RM_ECX dword [ebp+32]
+%define RM_CX word [ebp+32]
+%define RM_HCX word [ebp+34]
+%define RM_CL byte [ebp+32]
+%define RM_CH byte [ebp+33]
+
+%define RM_EAX dword [ebp+36]
+%define RM_AX word [ebp+36]
+%define RM_HAX word [ebp+38]
+%define RM_AL byte [ebp+36]
+%define RM_AH byte [ebp+37]
+
+%define RM_EFLAGS dword [ebp+40]
+%define RM_FLAGS word [ebp+40]
+%define RM_HFLAGS word [ebp+42]
+%define RM_FLAGSL byte [ebp+40]
+%define RM_FLAGSH byte [ebp+41]
+
+; Convenience macro to call a PM function
+%macro pm_call 1
+ push dword %1
+ call _pm_call
+%endmacro
+
+%endif ; PMCALL_INC
diff --git a/core/prefix.inc b/core/prefix.inc
new file mode 100644
index 00000000..9c8724b5
--- /dev/null
+++ b/core/prefix.inc
@@ -0,0 +1,17 @@
+;
+; The prefix is a small structure that prefaces the actual code;
+; it gives the compression program necessary information.
+;
+
+ section .prefix nowrite progbits align=16
+pfx_start dd _start ; Start of raw chunk
+pfx_compressed dd __pm_code_lma ; Start of compressed chunk
+pfx_cdatalen dd lzo_data_size ; Pointer to compressed size field
+%if IS_ISOLINUX
+pfx_checksum dd bi_length ; File length and checksum fields
+%else
+pfx_checksum dd 0 ; No checksum
+%endif
+pfx_maxlma dd MaxLMA ; Maximum size
+
+ section .text16
diff --git a/core/printf.c b/core/printf.c
new file mode 100644
index 00000000..b1b0466b
--- /dev/null
+++ b/