Initial commit
authorRobert Pengelly <robertapengelly@hotmail.com>
Wed, 31 Jul 2024 15:05:26 +0000 (16:05 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Wed, 31 Jul 2024 15:05:26 +0000 (16:05 +0100)
155 files changed:
.gitmodules [new file with mode: 0644]
Makefile.unix [new file with mode: 0644]
Makefile.w32 [new file with mode: 0644]
build/chimaera.img [new file with mode: 0644]
build/chimaera.vhd [new file with mode: 0644]
src/Makefile.unix [new file with mode: 0644]
src/Makefile.w32 [new file with mode: 0644]
src/apps/Makefile.unix [new file with mode: 0644]
src/apps/Makefile.w32 [new file with mode: 0644]
src/apps/hello/Makefile.unix [new file with mode: 0644]
src/apps/hello/Makefile.w32 [new file with mode: 0644]
src/apps/hello/crlf.asm [new file with mode: 0644]
src/apps/hello/hello.asm [new file with mode: 0644]
src/apps/hello/hello_.asm [new file with mode: 0644]
src/apps/hello/hello__.asm [new file with mode: 0644]
src/apps/hello/test.c [new file with mode: 0644]
src/apps/hello/writechr.asm [new file with mode: 0644]
src/apps/hello/writehex.asm [new file with mode: 0644]
src/apps/hello/writestr.asm [new file with mode: 0644]
src/apps/pcomm/Makefile.unix [new file with mode: 0644]
src/apps/pcomm/Makefile.w32 [new file with mode: 0644]
src/apps/pcomm/cbreak.asm [new file with mode: 0644]
src/apps/pcomm/commands [new file with mode: 0644]
src/apps/pcomm/crlf.asm [new file with mode: 0644]
src/apps/pcomm/date.asm [new file with mode: 0644]
src/apps/pcomm/dir.asm [new file with mode: 0644]
src/apps/pcomm/erase.asm [new file with mode: 0644]
src/apps/pcomm/exit.asm [new file with mode: 0644]
src/apps/pcomm/genhash.c [new file with mode: 0644]
src/apps/pcomm/genver.c [new file with mode: 0644]
src/apps/pcomm/history.asm [new file with mode: 0644]
src/apps/pcomm/pcomm.asm [new file with mode: 0644]
src/apps/pcomm/time.asm [new file with mode: 0644]
src/apps/pcomm/type.asm [new file with mode: 0644]
src/apps/pcomm/vector.asm [new file with mode: 0644]
src/apps/pcomm/writechr.asm [new file with mode: 0644]
src/apps/pcomm/writedec.asm [new file with mode: 0644]
src/apps/pcomm/writehex.asm [new file with mode: 0644]
src/apps/pcomm/writestr.asm [new file with mode: 0644]
src/apps/pcomm/xmalloc.asm [new file with mode: 0644]
src/apps/pcomm/xstrcpy.asm [new file with mode: 0644]
src/boot/Makefile.unix [new file with mode: 0644]
src/boot/Makefile.w32 [new file with mode: 0644]
src/boot/freeldr/Makefile.unix [new file with mode: 0644]
src/boot/freeldr/Makefile.w32 [new file with mode: 0644]
src/boot/freeldr/bootsect/Makefile.unix [new file with mode: 0644]
src/boot/freeldr/bootsect/Makefile.w32 [new file with mode: 0644]
src/boot/freeldr/bootsect/fat32_chs.asm [new file with mode: 0644]
src/boot/freeldr/bootsect/oldfat.asm [new file with mode: 0644]
src/boot/freeldr/core/Makefile.unix [new file with mode: 0644]
src/boot/freeldr/core/Makefile.w32 [new file with mode: 0644]
src/boot/freeldr/core/bootstrap.asm [new file with mode: 0644]
src/boot/freeldr/core/config.asm [new file with mode: 0644]
src/boot/freeldr/core/crlf.asm [new file with mode: 0644]
src/boot/freeldr/core/disk.asm [new file with mode: 0644]
src/boot/freeldr/core/error.asm [new file with mode: 0644]
src/boot/freeldr/core/fat.asm [new file with mode: 0644]
src/boot/freeldr/core/fat.inc [new file with mode: 0644]
src/boot/freeldr/core/file.asm [new file with mode: 0644]
src/boot/freeldr/core/freeldr.asm [new file with mode: 0644]
src/boot/freeldr/core/int21.asm [new file with mode: 0644]
src/boot/freeldr/core/ll.asm [new file with mode: 0644]
src/boot/freeldr/core/mangle.asm [new file with mode: 0644]
src/boot/freeldr/core/mem.asm [new file with mode: 0644]
src/boot/freeldr/core/menu.asm [new file with mode: 0644]
src/boot/freeldr/core/screen.asm [new file with mode: 0644]
src/boot/freeldr/core/search.asm [new file with mode: 0644]
src/boot/freeldr/core/vector.asm [new file with mode: 0644]
src/boot/freeldr/core/walk.asm [new file with mode: 0644]
src/boot/freeldr/core/writechr.asm [new file with mode: 0644]
src/boot/freeldr/core/writedec.asm [new file with mode: 0644]
src/boot/freeldr/core/writehex.asm [new file with mode: 0644]
src/boot/freeldr/core/writestr.asm [new file with mode: 0644]
src/boot/freeldr/core/xmalloc.asm [new file with mode: 0644]
src/boot/freeldr/core/xrealloc.asm [new file with mode: 0644]
src/boot/freeldr/freeldr.cfg [new file with mode: 0644]
src/boot/freeldr/genhash.c [new file with mode: 0644]
src/boot/freeldr/keywords [new file with mode: 0644]
src/boot/freeldr/libc/Makefile.unix [new file with mode: 0644]
src/boot/freeldr/libc/Makefile.w32 [new file with mode: 0644]
src/boot/freeldr/libc/stdio/fclose.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdio/feof.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdio/fopen.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdio/fread.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdlib/free.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdlib/malloc.asm [new file with mode: 0644]
src/boot/freeldr/libc/stdlib/realloc.asm [new file with mode: 0644]
src/boot/freeldr/libc/string/memmove.asm [new file with mode: 0644]
src/boot/freeldr/libc/string/strlen.asm [new file with mode: 0644]
src/boot/mbr/Makefile.unix [new file with mode: 0644]
src/boot/mbr/Makefile.w32 [new file with mode: 0644]
src/boot/mbr/dosmbr.asm [new file with mode: 0644]
src/kernel/Makefile.unix [new file with mode: 0644]
src/kernel/Makefile.w32 [new file with mode: 0644]
src/kernel/bootstrap.asm [new file with mode: 0644]
src/kernel/crlf.asm [new file with mode: 0644]
src/kernel/disk.asm [new file with mode: 0644]
src/kernel/divide.asm [new file with mode: 0644]
src/kernel/error.asm [new file with mode: 0644]
src/kernel/fat.asm [new file with mode: 0644]
src/kernel/fat.inc [new file with mode: 0644]
src/kernel/file.asm [new file with mode: 0644]
src/kernel/find.asm [new file with mode: 0644]
src/kernel/int21.asm [new file with mode: 0644]
src/kernel/int23.asm [new file with mode: 0644]
src/kernel/invalid.asm [new file with mode: 0644]
src/kernel/kernel.asm [new file with mode: 0644]
src/kernel/kmalloc.asm [new file with mode: 0644]
src/kernel/krealloc.asm [new file with mode: 0644]
src/kernel/mangle.asm [new file with mode: 0644]
src/kernel/mem.asm [new file with mode: 0644]
src/kernel/prog.asm [new file with mode: 0644]
src/kernel/query.asm [new file with mode: 0644]
src/kernel/search.asm [new file with mode: 0644]
src/kernel/vector.asm [new file with mode: 0644]
src/kernel/walk.asm [new file with mode: 0644]
src/kernel/writechr.asm [new file with mode: 0644]
src/kernel/writedec.asm [new file with mode: 0644]
src/kernel/writehex.asm [new file with mode: 0644]
src/kernel/writestr.asm [new file with mode: 0644]
src/lib/Makefile.unix [new file with mode: 0644]
src/lib/Makefile.w32 [new file with mode: 0644]
src/lib/crt/Makefile.unix [new file with mode: 0644]
src/lib/crt/Makefile.w32 [new file with mode: 0644]
src/lib/crt/crt0.asm [new file with mode: 0644]
src/lib/crt/ctype.asm [new file with mode: 0644]
src/lib/crt/include/stdio.inc [new file with mode: 0644]
src/lib/crt/include/sys/fcntl.inc [new file with mode: 0644]
src/lib/crt/stdio/fclose.asm [new file with mode: 0644]
src/lib/crt/stdio/feof.asm [new file with mode: 0644]
src/lib/crt/stdio/fgetc.asm [new file with mode: 0644]
src/lib/crt/stdio/flags.asm [new file with mode: 0644]
src/lib/crt/stdio/fopen.asm [new file with mode: 0644]
src/lib/crt/stdio/fread.asm [new file with mode: 0644]
src/lib/crt/stdio/fseek.asm [new file with mode: 0644]
src/lib/crt/stdio/ftell.asm [new file with mode: 0644]
src/lib/crt/stdlib/free.asm [new file with mode: 0644]
src/lib/crt/stdlib/malloc.asm [new file with mode: 0644]
src/lib/crt/stdlib/realloc.asm [new file with mode: 0644]
src/lib/crt/string/memmove.asm [new file with mode: 0644]
src/lib/crt/string/strchr.asm [new file with mode: 0644]
src/lib/crt/string/strcmp.asm [new file with mode: 0644]
src/lib/crt/string/strcpy.asm [new file with mode: 0644]
src/lib/crt/string/strlen.asm [new file with mode: 0644]
src/lib/crt/string/strrchr.asm [new file with mode: 0644]
src/lib/crt/udivmodsi4.asm [new file with mode: 0644]
src/utils/Makefile.unix [new file with mode: 0644]
src/utils/Makefile.w32 [new file with mode: 0644]
src/utils/binutils/Makefile.unix [new file with mode: 0644]
src/utils/binutils/Makefile.w32 [new file with mode: 0644]
src/utils/binutils/ar [new submodule]
src/utils/binutils/as [new submodule]
src/utils/binutils/ld [new submodule]
src/utils/dosfstools [new submodule]
src/utils/parted [new submodule]

diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..d2d3788
--- /dev/null
@@ -0,0 +1,15 @@
+[submodule "src/utils/dosfstools"]
+       path = src/utils/dosfstools
+       url = https://git.candlhat.org/dosfstools.git
+[submodule "src/utils/parted"]
+       path = src/utils/parted
+       url = https://git.candlhat.org/parted.git
+[submodule "src/utils/binutils/ar"]
+       path = src/utils/binutils/ar
+       url = https://git.candlhat.org/sar.git
+[submodule "src/utils/binutils/as"]
+       path = src/utils/binutils/as
+       url = https://git.candlhat.org/sasm.git
+[submodule "src/utils/binutils/ld"]
+       path = src/utils/binutils/ld
+       url = https://git.candlhat.org/slink.git
diff --git a/Makefile.unix b/Makefile.unix
new file mode 100644 (file)
index 0000000..c45ff74
--- /dev/null
@@ -0,0 +1,19 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+MAKE                +=  -r --quiet --no-print-directory
+MAKEFLAGS           +=  -r --quiet --no-print-directory
+
+OBJDIR              ?=  $(CURDIR)/build
+SRCDIR              ?=  $(CURDIR)/src
+
+PRIVATE-TARGETS     :=  spotless
+MAKECMDGOALS        ?=  all
+
+.PHONY: $(filter-out $(PRIVATE-TARGETS), $(MAKECMDGOALS))
+$(filter-out $(PRIVATE-TARGETS), $(MAKECMDGOALS)):
+       if [ ! -d "$(OBJDIR)" ]; then mkdir -p "$(OBJDIR)"; fi
+       $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/Makefile.unix" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)" $(MAKECMDGOALS)
+
+spotless:
+       if [ -d "$(OBJDIR)" ]; then rm -rf "$(OBJDIR)"; fi
diff --git a/Makefile.w32 b/Makefile.w32
new file mode 100644 (file)
index 0000000..f728417
--- /dev/null
@@ -0,0 +1,19 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+MAKE                +=  -r --quiet --no-print-directory
+MAKEFLAGS           +=  -r --quiet --no-print-directory
+
+OBJDIR              ?=  $(CURDIR)/build
+SRCDIR              ?=  $(CURDIR)/src
+
+PRIVATE-TARGETS     :=  spotless
+MAKECMDGOALS        ?=  all
+
+.PHONY: $(filter-out $(PRIVATE-TARGETS), $(MAKECMDGOALS))
+$(filter-out $(PRIVATE-TARGETS), $(MAKECMDGOALS)):
+       if not exist "$(OBJDIR)" ( mkdir "$(OBJDIR)" )
+       $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/Makefile.w32" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)" $(MAKECMDGOALS)
+
+spotless:
+       if exist "$(OBJDIR)" ( rmdir /q /s "$(OBJDIR)" )
diff --git a/build/chimaera.img b/build/chimaera.img
new file mode 100644 (file)
index 0000000..a1adb6e
Binary files /dev/null and b/build/chimaera.img differ
diff --git a/build/chimaera.vhd b/build/chimaera.vhd
new file mode 100644 (file)
index 0000000..63ee89c
Binary files /dev/null and b/build/chimaera.vhd differ
diff --git a/src/Makefile.unix b/src/Makefile.unix
new file mode 100644 (file)
index 0000000..2f65ea2
--- /dev/null
@@ -0,0 +1,49 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  utils boot lib kernel apps
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for d in $(TARGETS); do \
+         if [ ! -d "$(OBJDIR)/$$d" ]; then mkdir -p "$(OBJDIR)/$$d"; fi; \
+         $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" all; \
+       done
+
+clean:
+       for d in $(TARGETS); do \
+         if [ -d "$(OBJDIR)/$$d" ]; then \
+           $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" clean; \
+         fi; \
+       done
+       if [ -f freeldr.cfg ]; then rm -rf freeldr.cfg; fi
+
+chimaera.img: all
+       if [ -f $@ ]; then rm -rf $@; fi
+
+       utils/dosfstools/mkdosfs --boot boot/freeldr/bootsect/fat12.bin --sectors 720 -F 12 -n "CHIMAERA OS" $@
+       utils/dosfstools/mmd -i $@ boot boot/freeldr
+
+       utils/dosfstools/mcopy -i $@ $(SRCDIR)/boot/freeldr/freeldr.cfg ::/boot/freeldr/
+       utils/dosfstools/mcopy -i $@ boot/freeldr/core/freeldr.sys ::
+       utils/dosfstools/mcopy -i $@ kernel/kernel.sys ::
+       utils/dosfstools/mcopy -i $@ apps/pcomm/pcomm.com ::command.com
+
+chimaera.vhd: all
+       if [ -f $@ ]; then rm -rf $@; fi
+
+       utils/parted/parted --arca --boot boot/mbr/dosmbr.bin mkpart 128,11,17,66623 $@
+       utils/dosfstools/mkdosfs --arca --boot boot/freeldr/bootsect/fat32_chs.bin --offset 17 --sectors 66623 -F 32 -n "CHIMAERA OS" $@
+
+       utils/dosfstools/mmd --arca --offset 17 -i $@ boot boot/freeldr
+
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ $(SRCDIR)/boot/freeldr/freeldr.cfg ::/boot/freeldr/
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ boot/freeldr/core/freeldr.sys ::
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ kernel/kernel.sys ::
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ apps/pcomm/pcomm.com ::command.com
+
+run-qemu: chimaera.img chimaera.vhd
+       qemu-system-i386 -cpu 486 -drive file="chimaera.img",format=raw,if=floppy,index=0 -m 4M
+       qemu-system-i386 -cpu 486 -drive file="chimaera.vhd",format=raw,if=ide,index=0 -m 4M
diff --git a/src/Makefile.w32 b/src/Makefile.w32
new file mode 100644 (file)
index 0000000..ce995b5
--- /dev/null
@@ -0,0 +1,47 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  utils boot lib kernel apps
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%d in ($(TARGETS)) do ( \
+         ( if not exist "$(OBJDIR)/%%d" ( mkdir "$(OBJDIR)/%%d" ) ) & \
+         $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" all \
+       )
+
+clean:
+       for %%d in ($(TARGETS)) do ( \
+         if exist "$(OBJDIR)/%%d" ( \
+           $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" clean \
+         ) \
+       )
+       if exist freeldr.cfg ( del /q freeldr.cfg )
+
+chimaera.img: all
+       if exist $@ ( del /q $@ )
+
+       utils/dosfstools/mkdosfs --boot boot/freeldr/bootsect/fat12.bin --sectors 320 -F 12 -n "CHIMAERA OS" $@
+       utils/dosfstools/mmd -i $@ boot boot/freeldr
+
+       utils/dosfstools/mcopy -i $@ $(SRCDIR)/boot/freeldr/freeldr.cfg ::/boot/freeldr/
+       utils/dosfstools/mcopy -i $@ boot/freeldr/core/freeldr.sys ::
+       utils/dosfstools/mcopy -i $@ kernel/kernel.sys ::
+
+chimaera.vhd: all
+       if exist $@ ( del /q $@ )
+
+       utils/parted/parted --arca --boot boot/mbr/dosmbr.bin mkpart 128,11,17,65535 $@
+       utils/dosfstools/mkdosfs --arca --boot boot/freeldr/bootsect/fat16.bin --offset 17 --sectors 65535 -F 16 -n "CHIMAERA OS" $@
+
+       utils/dosfstools/mmd --arca --offset 17 -i $@ boot boot/freeldr
+
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ $(SRCDIR)/boot/freeldr/freeldr.cfg ::/boot/freeldr/
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ boot/freeldr/core/freeldr.sys ::
+       utils/dosfstools/mcopy --arca --offset 17 -i $@ kernel/kernel.sys ::
+
+run-qemu: chimaera.img chimaera.vhd
+       qemu-system-i386 -cpu 486 -drive file="chimaera.img",format=raw,if=floppy,index=0 -m 4M
+       qemu-system-i386 -cpu 486 -drive file="chimaera.vhd",format=raw,if=ide,index=0 -m 4M
diff --git a/src/apps/Makefile.unix b/src/apps/Makefile.unix
new file mode 100644 (file)
index 0000000..a4867ff
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  hello pcomm
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for t in $(TARGETS); do \
+               if [ ! -d "$(OBJDIR)/$$t" ]; then mkdir -p "$(OBJDIR)/$$t"; fi; \
+               $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" all; \
+       done
+
+clean:
+       for t in $(TARGETS); do \
+               if [ -d "$(OBJDIR)/$$t" ]; then \
+                       $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" clean; \
+               fi; \
+       done
diff --git a/src/apps/Makefile.w32 b/src/apps/Makefile.w32
new file mode 100644 (file)
index 0000000..1deffdb
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  hello pcomm
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%t in ($(TARGETS)) do ( \
+               ( if not exist "$(OBJDIR)/%%t" ( mkdir "$(OBJDIR)/%%t" ) ) & \
+               $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" all \
+       )
+
+clean:
+       for %%t in ($(TARGETS)) do ( \
+               if exist "$(OBJDIR)/%%t" ( \
+                       $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" clean \
+               ) \
+       )
diff --git a/src/apps/hello/Makefile.unix b/src/apps/hello/Makefile.unix
new file mode 100644 (file)
index 0000000..07d771f
--- /dev/null
@@ -0,0 +1,21 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+#all: hello.com test.asm
+all: hello.com
+
+clean:
+       for f in *.o; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in *.lst; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       if [ -f hello.com ]; then rm -rf hello.com; fi
+
+hello.com: ../../lib/crt/crt0.o crlf.o hello.o writechr.o writehex.o writestr.o ../../lib/crt/libc.a
+       ../../utils/binutils/slink --oformat msdos -o $@ $^
+
+%.o: %.asm
+       ../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/apps/hello/Makefile.w32 b/src/apps/hello/Makefile.w32
new file mode 100644 (file)
index 0000000..369b9c6
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: hello.com
+
+clean:
+       for %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+       if exist hello.com ( del /q hello.com )
+
+hello.com: ../../lib/crt/crt0.o crlf.o hello.o writechr.o writehex.o writestr.o ../../lib/crt/libc.a
+       ../../utils/binutils/slink --oformat msdos -o $@ $^
+
+%.o: %.asm
+       ../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/apps/hello/crlf.asm b/src/apps/hello/crlf.asm
new file mode 100644 (file)
index 0000000..330dedf
--- /dev/null
@@ -0,0 +1,31 @@
+;******************************************************************************
+; @file             crlf.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _crlf
+;******************************************************************************
+global      _crlf
+_crlf:
+
+    push    ax
+    push    bx
+    push    dx
+    push    bp
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0A)
+    int     HEX (21)
+    
+    pop     bp
+    pop     dx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/hello/hello.asm b/src/apps/hello/hello.asm
new file mode 100644 (file)
index 0000000..f477f8e
--- /dev/null
@@ -0,0 +1,40 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            hello.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _free
+;******************************************************************************
+global      _main
+_main:
+
+    mov     bx,     offset msg_hello
+    
+    call    _writestr
+    call    _crlf
+    
+    mov     ah,     HEX (08)
+    int     HEX (21)
+    
+    call    _writehex
+    call    _crlf
+    
+    mov     ah,     HEX (07)
+    int     HEX (21)
+    
+    call    _writehex
+    call    _crlf
+    
+    xor     ax,     ax
+    int     HEX (16)
+    
+    xor     ax,     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+msg_hello:                      db      "Hello, world!",        HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/apps/hello/hello_.asm b/src/apps/hello/hello_.asm
new file mode 100644 (file)
index 0000000..3ae4d08
--- /dev/null
@@ -0,0 +1,102 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            hello.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _free
+;******************************************************************************
+global      _main
+_main:
+
+    mov     bx,     offset msg_hello
+    
+    call    _writestr
+    call    _crlf
+    
+    mov     bx,     offset msg_malloc1
+    call    _writestr
+    
+    mov     ax,     64
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    call    _writehex
+    call    _crlf
+    
+    mov     bx,     offset msg_free1
+    call    _writestr
+    
+    call    _writehex
+    call    _crlf
+    
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    mov     bx,     offset msg_malloc2
+    call    _writestr
+    
+    mov     ax,     64
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    call    _writehex
+    call    _crlf
+    
+    mov     bx,     offset msg_free2
+    call    _writestr
+    
+    call    _writehex
+    call    _crlf
+    
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    mov     di,     offset fn_config
+    push    di
+    
+    call    _fopen
+    add     sp,     2
+    
+    call    _writehex
+    call    _crlf
+    
+    mov     di,     offset fn_config
+    push    di
+    
+    call    _fopen
+    add     sp,     2
+    
+    call    _writehex
+    call    _crlf
+    
+    xor     ax,     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+msg_hello:                      db      "Hello, world!",        HEX (0D),   HEX (0A),   HEX (00)
+fn_config:                      db      "test.txt",             HEX (00)
+
+msg_malloc1:                    db      "First malloc: ",       HEX (00)
+msg_free1:                      db      "First free: ",         HEX (00)
+
+msg_malloc2:                    db      "Second malloc: ",      HEX (00)
+msg_free2:                      db      "Second free: ",        HEX (00)
diff --git a/src/apps/hello/hello__.asm b/src/apps/hello/hello__.asm
new file mode 100644 (file)
index 0000000..8916479
--- /dev/null
@@ -0,0 +1,517 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            hello.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _main
+;******************************************************************************
+global      _main
+_main:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     8
+    
+;    push    es
+;    push    ds
+;    push    bx
+;    push    cx
+;    push    si
+;    
+;    mov     ax,     cs:[HEX (16)]
+;    
+;    and     ax,     ax
+;    jnz     yay
+;    
+;    xor     ax,     ax
+;    int     0x19
+;
+;yay:
+;
+;    mov     ax,     cs
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     ax,     ds
+;    call    _writehex
+;    call    _crlf
+;    
+;    mov     ax,     es
+;    call    _writehex
+;    call    _crlf
+    
+;    mov     bx,     offset msg_hello
+;    
+;    call    _writestr
+;    call    _crlf
+    
+;    mov     ax,     HEX (0006)
+;    int     HEX (10)
+;    
+;    xor     ax,     ax
+;    xor     dx,     dx
+;    
+;    mov     cx,     320
+;    mov     si,     1
+;
+;test_loop:
+;
+;    push    si
+;    push    dx
+;    push    ax
+;    
+;    call    _gdi_point
+;    add     sp,     6
+;    
+;    add     ax,     1
+;    add     dx,     1
+;    
+;    loop    test_loop
+;    
+;    xor     ax,     ax
+;    int     HEX (16)
+    
+;    mov     ax,     HEX (0006)
+;    int     HEX (10)
+;    
+;    xor     ax,     ax
+;    xor     dx,     dx
+;    
+;    mov     cx,     50
+;    mov     si,     1
+;
+;test_loop:
+;
+;    push    si
+;    push    dx
+;    push    ax
+;    
+;    call    _gdi_point
+;    add     sp,     6
+;    
+;    add     ax,     1
+;    add     dx,     1
+;    
+;    loop    test_loop
+;    
+;    xor     ax,     ax
+;    int     HEX (16)
+    
+    mov     ax,     HEX (0004)
+    int     HEX (10)
+    
+;    mov     ax,     HEX (0B00)
+;    mov     bx,     HEX (0001)
+;    int     HEX (10)
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    mov     si,     offset _cursor
+    
+    lodsw
+    mov     word ptr [bp - 8],      ax
+    
+    lodsw
+    mov     word ptr [bp - 6],      ax
+    
+    mov     ax,     word ptr [bp - 8]
+    xor     dx,     dx
+    
+    mul     word ptr [bp - 6]
+    mov     cx,     ax
+    
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 2],      0
+
+draw_loop:
+
+    and     cx,     cx
+    jz      draw_done
+    
+    mov     ax,     word ptr [bp - 2]
+    
+    and     ax,     ax
+    jz      draw_pixel
+    
+    and     ax,     word ptr [bp - 8]
+    jz      draw_pixel
+    
+    mov     word ptr [bp - 2],      0
+    inc     word ptr [bp - 4]
+
+draw_pixel:
+
+    lodsw
+    
+    cmp     ah,     127
+    jae     draw_next
+
+draw_fg:
+
+    xor     ah,     ah
+    push    ax
+    
+    push    word ptr [bp - 4]
+    push    word ptr [bp - 2]
+    
+    call    _gdi_point
+    add     sp,     6
+
+draw_next:
+
+    inc     word ptr [bp - 2]
+    
+    dec     cx
+    jmp     draw_loop
+
+draw_done:
+
+    xor     ax,     ax
+    int     HEX (16)
+    
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+;    mov     si,     word ptr [bp + 6]
+;    mov     bx,     [si + 0]
+;    
+;    and     bx,     bx
+;    jz      after_name
+;    
+;    call    _writestr
+;    call    _crlf
+
+after_name:
+
+;    mov     ah,     HEX (3C)
+;    mov     cx,     HEX (20)
+;    mov     dx,     offset fn_config
+;    int     HEX (21)
+;    jc      .error
+;    
+;    mov     bx,     ax
+;    
+;    mov     ah,     HEX (40)
+;    mov     cx,     8
+;    mov     dx,     offset msg_hello
+;    int     HEX (21)
+;    jc      .error
+;    
+;    mov     ah,     HEX (3E)
+;    int     HEX (21)
+;    jc      .error
+;    
+;    mov     ax,     offset fn_flags
+;    push    ax
+;    
+;    mov     ax,     offset fn_config
+;    push    ax
+;    
+;    call    _fopen
+;    add     sp,     4
+;    
+;    and     ax,     ax
+;    jz      .error
+;    
+;    push    ax
+;    
+;    call    _fclose
+;    add     sp,     2
+;    
+;    and     ax,     ax
+;    jnz     .error
+;    
+;    mov     ax,     offset fn_flags
+;    push    ax
+;    
+;    mov     ax,     offset fn_config
+;    push    ax
+;    
+;    call    _fopen
+;    add     sp,     4
+;
+;    mov     ah,     HEX (0A)
+;    mov     dx,     offset scratch_sz
+;    int     HEX (21)
+;    
+;    mov     ax,     cs:[HEX (2C)]
+;    
+;    and     ax,     ax
+;    jz      exit
+;    
+;    call    _writehex
+;    call    _crlf
+;    
+;    xor     ax,     ax
+;    int     0x16
+;    
+;    mov     ds,     ax
+;    xor     bx,     bx
+;    
+;    xor     cx,     cx
+;
+;again:
+;
+;    push    bx
+;    
+;    call    _strlen
+;    add     sp,     2
+;    
+;    and     ax,     ax
+;    jz      done
+;    
+;    add     ax,     1
+;    add     bx,     ax
+;    
+;    jmp     again
+;
+;done:
+;
+;    mov     cx,     bx
+;    xor     si,     si
+;
+;print:
+;
+;    and     cx,     cx
+;    jz      exit
+;    
+;    lodsb
+;    
+;    call    _writechr
+;    dec     cx
+;    
+;    jmp     print
+;
+;exit:
+;
+;    pop     si
+;    pop     cx
+;    pop     bx
+;    pop     ds
+;    pop     es
+;    pop     bp
+    
+    xor     ax,     ax
+    
+    add     sp,     8
+    clc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _gdi_point
+;******************************************************************************
+_gdi_point:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    ax
+    push    bx
+    push    cx
+    push    di
+    push    es
+    
+    mov     ax,     HEX (B800)
+    mov     es,     ax
+    
+    mov     bx,     word ptr [bp + 6]
+    mov     cx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (0F)
+    int     HEX (10)
+    
+    cmp     al,     HEX (04)
+    jb      _gdi_point.done
+    
+    cmp     al,     HEX (05)
+    jna     _gdi_point.4ppb
+    
+    cmp     al,     HEX (06)
+    jne     _gdi_point.done
+
+_gdi_point.8ppb:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Offset = 4 * 8192 if y odd.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    shr     bx
+    rcr     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add 4 * 80 * (y / 2) to offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xchg    bh,     bl
+    add     di,     bx
+    shr     bx
+    shr     bx
+    add     di,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide x by 2 and add it to the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cx
+    shr     ax
+    add     di,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Compute x mod 8 and divide di by 4.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    shr     di
+    shr     di
+    and     cl,     7
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Compute color and mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     byte ptr [bp + 8]
+    mov     al,     HEX (7F)
+    
+    ror     al,     cl
+    inc     cl
+    ror     ah,     cl
+    
+    jmp     _gdi_point.draw_pixels
+
+_gdi_point.4ppb:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Offset = 4 * 8192 if y odd.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    shr     bx
+    rcr     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add 4 * 80 * (y / 2) to offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xchg    bh,     bl
+    add     di,     bx
+    shr     bx
+    shr     bx
+    add     di,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Compute x mod 4 and divide di by 4.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     di,     cx
+    shr     di
+    shr     di
+    and     cl,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Compute color and mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     byte ptr [bp + 8]
+    mov     al,     HEX (3F)
+    
+    shl     cl
+    ror     al,     cl
+    
+    inc     cl
+    inc     cl
+    ror     ah,     cl
+
+_gdi_point.draw_pixels:
+
+    and     al,     es:[di]
+    or      al,     ah
+    stosb
+
+_gdi_point.done:
+
+    pop     es
+    pop     di
+    pop     cx
+    pop     bx
+    pop     ax
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_cursor:
+
+    dw      HEX (0008),     HEX (0008)
+    
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (03),       HEX (00)
+    db      HEX (03),       HEX (00)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+    db      HEX (00),       HEX (7f)
+
+;msg_hello:                      db      "Hello, world!",                    HEX (00)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; int21/ah=0A variables.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;scratch_sz:                     db      32
+;scratch_len:                    db      0
+;
+;scratch:                        db      34      dup (0)
diff --git a/src/apps/hello/test.c b/src/apps/hello/test.c
new file mode 100644 (file)
index 0000000..dc8fabd
--- /dev/null
@@ -0,0 +1,6 @@
+/******************************************************************************
+ * @file            hello.c
+ *****************************************************************************/
+int main (int argc, char **argv) {
+    return 0;
+}
diff --git a/src/apps/hello/writechr.asm b/src/apps/hello/writechr.asm
new file mode 100644 (file)
index 0000000..b268990
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             writechr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         writechr
+;******************************************************************************
+global      _writechr
+_writechr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    bp                                                                  ; Some BIOSes destroy BP when the screen scrolls
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/apps/hello/writehex.asm b/src/apps/hello/writehex.asm
new file mode 100644 (file)
index 0000000..7571729
--- /dev/null
@@ -0,0 +1,64 @@
+;******************************************************************************
+; @file             writehex.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+global      _writehex
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     cs:[_writehex_num_digits]
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _writehex_num_digits
+_writehex_num_digits:           dw      HEX (0004)
diff --git a/src/apps/hello/writestr.asm b/src/apps/hello/writestr.asm
new file mode 100644 (file)
index 0000000..586b3de
--- /dev/null
@@ -0,0 +1,74 @@
+;******************************************************************************
+; @file             writestr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _writestr
+;******************************************************************************
+global      _writestr
+_writestr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    si
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize si with bx
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump over our printing code to get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _writestr.next
+
+_writestr.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 02h - MSDOS print chareacter
+    ;;     DL       - Character to print
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+
+_writestr.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _writestr.print
+
+_writestr.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     si
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/apps/pcomm/Makefile.unix b/src/apps/pcomm/Makefile.unix
new file mode 100644 (file)
index 0000000..4b669c3
--- /dev/null
@@ -0,0 +1,53 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: cmdhash.gen ver.inc pcomm.com
+
+clean:
+       for f in *.o; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in *.lst; do if [ -f $$f ]; then rm -rf $$f; fi; done
+
+       if [ -f cmdhash.gen ]; then rm -rf cmdhash.gen; fi
+       if [ -f pcomm.com ]; then rm -rf pcomm.com; fi
+       if [ -f ver.inc ]; then rm -rf ver.inc; fi
+
+ifeq ($(OS), Windows_NT)
+cmdhash.gen: commands genhash.exe
+       ./genhash.exe < $< > $@
+       rm -rf genhash.exe
+
+ver.inc: genver.exe
+       ./genver.exe > $@
+       rm -rf genver.exe
+
+genhash.exe: genhash.c
+       gcc -o $@ $^
+
+genver.exe: genver.c
+       gcc -o $@ $^
+else
+cmdhash.gen: commands genhash
+       ./genhash < $< > $@
+       rm -rf genhash
+
+ver.inc: genver
+       ./genver > $@
+       rm -rf genver
+
+genhash: genhash.c
+       gcc -o $@ $^
+
+genver: genver.c
+       gcc -o $@ $^
+endif
+
+pcomm.com: ../../lib/crt/crt0.o cbreak.o crlf.o date.o dir.o erase.o exit.o history.o pcomm.o time.o type.o vector.o writedec.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
+       ../../utils/binutils/slink --oformat msdos -o $@ $^
+
+%.o: %.asm
+       ../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/apps/pcomm/Makefile.w32 b/src/apps/pcomm/Makefile.w32
new file mode 100644 (file)
index 0000000..994bad8
--- /dev/null
@@ -0,0 +1,37 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: cmdhash.gen ver.inc pcomm.com
+
+clean:
+       for %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+
+       if exist cmdhash.gen ( del /q cmdhash.gen )
+       if exist pcomm.com ( del /q pcomm.com )
+       if exist ver.inc ( del /q ver.inc )
+
+cmdhash.gen: commands genhash.exe
+       genhash.exe < $< > $@
+       del /q genhash,exe
+
+ver.inc: genver.exe
+       genver.exe > $@
+       del /q genver.exe
+
+genhash.exe: genhash.c
+       gcc -o $@ $^
+
+genver.exe: genver.c
+       gcc -o $@ $^
+
+pcomm.com: ../../lib/crt/crt0.o cbreak.o crlf.o date.o dir.o erase.o exit.o history.o pcomm.o time.o type.o vector.o writedec.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
+       ../../utils/binutils/slink --oformat msdos -o $@ $^
+
+%.o: %.asm
+       ../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/apps/pcomm/cbreak.asm b/src/apps/pcomm/cbreak.asm
new file mode 100644 (file)
index 0000000..85ecd7d
--- /dev/null
@@ -0,0 +1,81 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            cbreak.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _cbreak_handler
+;******************************************************************************
+global      _cbreak_handler
+_cbreak_handler:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the extra segment and the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the extra segment is the same as the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up di and cx ready to clear the current command.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     offset _scratch
+    xor     ch,     ch
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the di and cx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out al and clear the current command.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     al,     al
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the cx (command length and current offset) and di
+    ;; (current command address) registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     cx
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset our history index (bp should be unchanged).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_history + 4]
+    mov     cs:[_history_idx],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free the current command history if there is one.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_curr_scratch]
+    
+    and     ax,     ax
+    jz      .L1
+    
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    xor     ax,     ax
+    mov     cs:[_curr_scratch],     ax
+
+.L1:
+
+    call    _prompt
+    
+    pop     ax
+    pop     es
+    
+    clc
+    retf 2
diff --git a/src/apps/pcomm/commands b/src/apps/pcomm/commands
new file mode 100644 (file)
index 0000000..0ccdbb5
--- /dev/null
@@ -0,0 +1,16 @@
+cd
+cls
+date
+del
+dir
+echo
+exit
+help
+mkdir
+reboot
+rmdir
+shutdown
+time
+touch
+type
+ver
diff --git a/src/apps/pcomm/crlf.asm b/src/apps/pcomm/crlf.asm
new file mode 100644 (file)
index 0000000..330dedf
--- /dev/null
@@ -0,0 +1,31 @@
+;******************************************************************************
+; @file             crlf.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _crlf
+;******************************************************************************
+global      _crlf
+_crlf:
+
+    push    ax
+    push    bx
+    push    dx
+    push    bp
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0A)
+    int     HEX (21)
+    
+    pop     bp
+    pop     dx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/pcomm/date.asm b/src/apps/pcomm/date.asm
new file mode 100644 (file)
index 0000000..359d292
--- /dev/null
@@ -0,0 +1,77 @@
+;******************************************************************************
+; @file             date.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _handler_date
+;******************************************************************************
+global      _handler_date
+_handler_date:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ah,     HEX (2A)
+    int     HEX (21)
+    mov     bx,     dx
+    
+    mov     ax,     cx
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '-'
+    int     HEX (21)
+    
+    cmp     bh,     10
+    jae     _handler_date.got_month
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '0'
+    int     HEX (21)
+
+_handler_date.got_month:
+
+    xor     ah,     ah
+    mov     al,     bh
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '-'
+    int     HEX (21)
+    
+    cmp     bl,     10
+    jae     _handler_date.got_day
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '0'
+    int     HEX (21)
+
+_handler_date.got_day:
+
+    xor     ah,     ah
+    mov     al,     bl
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0A)
+    int     HEX (21)
+
+_handler_date.done:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/pcomm/dir.asm b/src/apps/pcomm/dir.asm
new file mode 100644 (file)
index 0000000..a15c65e
--- /dev/null
@@ -0,0 +1,416 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            dir.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _handler_dir
+;******************************************************************************
+global      _handler_dir
+_handler_dir:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     6
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 6],      0
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 2],      0
+    
+    mov     ax,     64
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    mov     cs:[_dta_addr],     ax
+    push    ds
+    
+    mov     ds,     ax
+    xor     dx,     dx
+    
+    mov     ah,     HEX (1A)
+    int     HEX (21)
+    
+    pop     ds
+    
+    cmp     byte ptr [bx],      0
+    jne     _handler_dir.got_path
+    
+    mov     bx,     offset _fn_wild
+
+_handler_dir.got_path:
+
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     di,     offset _cmdline
+    mov     si,     bx
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    mov     bx,     offset _cmdline
+
+_handler_dir.store_file:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_dir.check2
+    
+    mov     si,     bx
+    push    si
+    
+    mov     ax,     offset _vec_files
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+
+_handler_dir.check:
+
+    mov     ax,     ' '
+    push    ax
+    
+    mov     si,     bx
+    push    si
+    
+    call    _strchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      _handler_dir.check2
+    
+    mov     bx,     ax
+    mov     byte ptr [bx],      0
+    
+    inc     bx
+
+_handler_dir.skip:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_dir.check2
+    
+    cmp     byte ptr [bx],      ' '
+    ja      _handler_dir.store_file
+    
+    inc     bx
+    jmp     _handler_dir.skip
+
+_handler_dir.check2:
+
+    cmp     word ptr cs:[_vec_files + 4],   1
+    jbe     _handler_dir.next
+    
+    mov     word ptr [bp - 4],      2
+
+_handler_dir.next:
+
+    mov     ax,     word ptr [bp - 6]
+    inc     ax
+    
+    cmp     ax,     cs:[_vec_files + 4]
+    ja      _handler_dir.free
+    
+    mov     word ptr [bp - 6],      ax
+    dec     ax
+    
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    push    es
+    
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     dx,     ax
+    
+    pop     es
+    
+    call    _walk_dir
+    jmp     _handler_dir.next
+
+_handler_dir.free:
+
+    mov     ax,     cs:[_dta_addr]
+    push    ax
+    
+    call    _free
+    add     sp,     2
+
+_handler_dir.cleanup:
+
+    mov     ax,     cs:[_vec_files + 0]
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     di,     offset _vec_files
+    xor     al,     al
+    
+    mov     cx,     6
+    rep     stosb
+
+_handler_dir.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     6
+    pop     bp
+    
+    ret
+
+;******************************************************************************
+; @function         _walk_dir
+;******************************************************************************
+_walk_dir:
+
+    push    ax
+    push    bx
+    push    dx
+    push    ds
+    push    cx
+    
+    mov     word ptr [bp - 2],      0
+    mov     si,     offset _file_path
+    
+    push    dx
+    push    si
+    
+    call    _xstrcpy
+    add     sp,     4
+    
+    cmp     word ptr [bp - 4],      1
+    jb      _walk_dir.find_first
+
+_walk_dir.find_first:
+
+    mov     ah,     HEX (4E)
+    xor     cx,     cx
+    int     HEX (21)
+    jnc     _walk_dir.check5
+    
+    cmp     ax,     2
+    jne     _walk_dir.check3
+    
+    mov     bx,     offset _err_no_file
+    jmp     _walk_dir.error
+
+_walk_dir.check3:
+
+    cmp     ax,     3
+    jne     _walk_dir.unhandled
+    
+    mov     bx,     offset _err_no_dir
+    jmp     _walk_dir.error
+
+_walk_dir.unhandled:
+
+    mov     bx,     offset _err_unhandled
+
+_walk_dir.error:
+
+    pop     cx
+    call    _writestr
+    
+    cmp     ax,     3
+    ja      _walk_dir.done
+    
+    cmp     ax,     2
+    jb      _walk_dir.done
+    
+    mov     bx,     offset _file_path
+    
+    call    _writestr
+    call    _crlf
+    
+    jmp     _walk_dir.done
+
+_walk_dir.check5:
+
+    cmp     word ptr [bp - 4],      2
+    jb     _walk_dir.setup
+    
+    mov     bx,     offset _file_path
+    call    _writestr
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ':'
+    int     HEX (21)
+    
+    call    _crlf
+
+_walk_dir.setup:
+
+    mov     ax,     cs:[_dta_addr]
+    mov     ds,     ax
+
+_walk_dir.find:
+
+    cmp     word ptr [bp - 2],      0
+    je      _walk_dir.ok
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ':'
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+
+_walk_dir.ok:
+
+    mov     si,     30
+    mov     cx,     12
+
+_walk_dir.print:
+
+    lodsb
+    
+    and     al,     al
+    jz      _walk_dir.final_pad
+    
+    cmp     al,     '.'
+    je      _walk_dir.check
+    
+    jmp     short   _walk_dir.output
+
+_walk_dir.check:
+
+    cmp     cx,     12
+    jb      _walk_dir.period_check
+    
+    jmp     short   _walk_dir.output
+
+_walk_dir.period_check:
+
+    cmp     byte ptr [si - 1],      '.'
+    jne     _walk_dir.pad
+
+_walk_dir.output:
+
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    dec     cx
+    jnz     _walk_dir.print
+
+_walk_dir.pad:
+
+    cmp     cx,     4
+    jb      _walk_dir.print
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+    
+    dec     cx
+    jmp     short   _walk_dir.pad
+
+_walk_dir.final_pad:
+
+    and     cx,     cx
+    jz      _walk_dir.check2
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+    
+    dec     cx
+    jmp     short   _walk_dir.final_pad
+
+_walk_dir.check2:
+
+    inc     word ptr [bp - 2]
+    
+    cmp     word ptr [bp - 2],      5
+    jb      _walk_dir.next
+    
+    mov     word ptr [bp - 2],      0
+    call    _crlf
+
+_walk_dir.next:
+
+    mov     ah,     HEX (4F)
+    int     HEX (21)
+    jnc     _walk_dir.find
+    
+    cmp     word ptr [bp - 2],      0
+    je      _walk_dir.check4
+    
+    call    _crlf
+
+_walk_dir.check4:
+
+    pop     cx
+    
+    cmp     word ptr [bp - 4],      2
+    jb      _walk_dir.done
+    
+    cmp     cx,     1
+    jbe     _walk_dir.done
+    
+    call    _crlf
+
+_walk_dir.done:
+
+    pop     ds
+    pop     dx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_vec_files:                     db      6       dup (0)
+_cmdline:                       db      256     dup (0)
+
+_file_path:                     db      256     dup (0)
+_dta_addr:                      dw      HEX (0000)
+
+_fn_wild:                       db      "*.*",      HEX (00)
+
+_err_no_dir:                    db      "Path not found: ",     HEX (00)
+_err_no_file:                   db      "File not found: ",     HEX (00)
+
+_err_unhandled:                 db      "Unhandled error code",     HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/apps/pcomm/erase.asm b/src/apps/pcomm/erase.asm
new file mode 100644 (file)
index 0000000..ebccc4e
--- /dev/null
@@ -0,0 +1,26 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            erase.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _erase_char
+;******************************************************************************
+global      _erase_char
+_erase_char:
+
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (08)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (20)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (08)
+    int     HEX (21)
+    
+    ret
diff --git a/src/apps/pcomm/exit.asm b/src/apps/pcomm/exit.asm
new file mode 100644 (file)
index 0000000..c88db9e
--- /dev/null
@@ -0,0 +1,28 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            exit.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _handler_exit
+;******************************************************************************
+global      _handler_exit
+_handler_exit:
+
+    push    ax
+    mov     ax,     cs:[HEX (16)]
+    
+    and     ax,     ax
+    jnz     _handler_exit.kill
+    
+    pop     ax
+    ret
+
+_handler_exit.kill:
+
+    pop     ax
+    
+    mov     ax,     HEX (4C00)
+    int     HEX (21)
diff --git a/src/apps/pcomm/genhash.c b/src/apps/pcomm/genhash.c
new file mode 100644 (file)
index 0000000..8cacbc4
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * @file            genhash.c
+ *****************************************************************************/
+#include    <ctype.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+struct hash {
+
+    char *keywd;
+    unsigned value;
+    
+    struct hash *next;
+    struct hash **prev;
+
+};
+
+static char *trim_whitespace (char *str) {
+
+    char *end;
+    
+    while (isspace ((int) *str)) {
+        str++;
+    }
+    
+    if (*str == '\0') {
+        return str;
+    }
+    
+    end = str + strlen (str) - 1;
+    
+    while (end > str && isspace ((int) *end)) {
+        end--;
+    }
+    
+    end[1] = '\0';
+    return str;
+
+}
+
+static void hash_push (struct hash **head, struct hash *item) {
+
+    item->prev = head;
+    
+    if (*head) {
+        (*head)->prev = &item->next;
+    }
+    
+    item->next = *head;
+    *head = item;
+
+}
+
+int main (int argc, char **argv) {
+
+    struct hash *curr_hash, *seen_hashes = 0;
+    
+    char ch, keywd[256], *p;
+    unsigned hash;
+    
+    while ((fgets (keywd, sizeof (keywd), stdin))) {
+    
+        p = trim_whitespace (keywd);
+        hash = 0;
+        
+        while ((ch = *p++)) {
+            hash = (((hash << 5) | (hash >> 11)) ^ (ch | 0x20)) & 0xffff;
+        }
+        
+        for (curr_hash = seen_hashes; curr_hash; curr_hash = curr_hash->next) {
+        
+            if (curr_hash->value == hash) {
+            
+                fprintf (stderr, "hash collision (0x%04x) %s %s\n", hash, keywd, curr_hash->keywd);
+                return 1;
+            
+            }
+        
+        }
+        
+        if (!(curr_hash = (struct hash *) malloc (sizeof (*curr_hash)))) {
+        
+            fprintf (stderr, "Out of memory");
+            return 1;
+        
+        }
+        
+        curr_hash->keywd = keywd;
+        curr_hash->value = hash;
+        
+        curr_hash->next = 0;
+        hash_push (&seen_hashes, curr_hash);
+        
+        printf ("hash_%s: equ 0x%04x\n", keywd, hash);
+    
+    }
+    
+    return 0;
+
+}
diff --git a/src/apps/pcomm/genver.c b/src/apps/pcomm/genver.c
new file mode 100644 (file)
index 0000000..14593b1
--- /dev/null
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * @file            genver.c
+ *****************************************************************************/
+#include    <stdio.h>
+#include    <time.h>
+
+int main (int argc, char **argv) {
+
+    time_t raw_time = time (0);
+    struct tm *ctime = localtime (&raw_time);
+    
+    printf ("_welcome_message: db \"Welcome to PCOMM (build %u.%u)\", HEX (0D), HEX (0A), HEX (00)\n",
+        ctime->tm_mday + ((ctime->tm_mon + 1) << 5) + ((ctime->tm_year - 80) << 9),
+            (ctime->tm_sec >> 1) + (ctime->tm_min << 5) + (ctime->tm_hour << 11)
+    );
+    
+    return 0;
+
+}
diff --git a/src/apps/pcomm/history.asm b/src/apps/pcomm/history.asm
new file mode 100644 (file)
index 0000000..0b9b695
--- /dev/null
@@ -0,0 +1,370 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            history.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _history_down
+;******************************************************************************
+global      _history_down
+_history_down:
+
+    push    es
+    push    ds
+    push    bx
+    
+    mov     ax,     cs:[_history_idx]
+    mov     dx,     cs:[_vec_history + 4]
+    
+    cmp     ax,     dx
+    jae     .L7
+    
+    xor     dx,     dx
+    inc     ax
+    mov     cs:[_history_idx],      ax
+    
+    mov     bx,     cs:[_curr_scratch]
+    mov     ds,     bx
+    xor     si,     si
+    
+    cmp     ax,     cs:[_vec_history + 4]
+    jae     .L10
+    
+    push    cx
+    
+    mov     cx,     2
+    mul     cx
+    
+    pop     cx
+    push    es
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_history]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    pop     es
+    
+    mov     ds,     ax
+    xor     si,     si
+
+.L10:
+
+    and     ch,     ch
+    jz      .L9
+    
+    xor     ah,     ah
+    mov     al,     cs:[_curr_col]
+    
+    push    cx
+    push    dx
+    xor     dx,     dx
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    add     ax,     cx
+    
+    mov     cx,     HEX (50)
+    div     cx
+    
+    xchg    ax,     dx
+    pop     dx
+    pop     cx
+    
+    and     ax,     ax
+    jnz     .L11
+    
+    push    ax
+    push    bx
+    push    dx
+    push    cx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    pop     cx
+    dec     dh
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (50)
+    int     HEX (10)
+    
+    mov     byte ptr es:[di],       0
+    call    _erase_char
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (4F)
+    int     HEX (10)
+    
+    pop     dx
+    pop     bx
+    pop     ax
+    
+    dec     ch
+    dec     di
+    
+    jmp     short   .L10
+
+.L11:
+
+    mov     byte ptr es:[di],       0
+    call    _erase_char
+    
+    dec     ch
+    dec     di
+    
+    jmp     short   .L10
+
+.L9:
+
+    lodsb
+    
+    or      al,     al
+    jz      .L7
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    stosb
+    inc     ch
+    
+    jmp     short   .L9
+
+.L7:
+
+    mov     ax,     ds
+    
+    and     ax,     ax
+    jz      .L8
+    
+    cmp     ax,     cs:[_curr_scratch]
+    jne     .L8
+    
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    xor     ax,     ax
+    mov     cs:[_curr_scratch],     ax
+
+.L8:
+
+    pop     bx
+    pop     ds
+    pop     es
+    
+    ret
+
+;******************************************************************************
+; @function         _history_up
+;******************************************************************************
+global      _history_up
+_history_up:
+
+    push    es
+    push    ds
+    push    bx
+    
+    mov     ax,     cs:[_history_idx]
+    xor     dx,     dx
+    
+    cmp     ax,     dx
+    jbe     .L1
+    
+    mov     bx,     cs:[_curr_scratch]
+    
+    and     bx,     bx
+    jnz     .L2
+    
+    push    ax
+    
+    xor     ah,     ah
+    mov     al,     ch
+    
+    xor     dx,     dx
+    inc     ax
+    
+    push    ax
+    push    dx
+    
+    call    _malloc
+    add     sp,     4
+    
+    mov     bx,     ax
+    pop     ax
+    
+    and     bx,     bx
+    jz      .L2
+    
+    mov     cs:[_curr_scratch],     bx
+    
+    push    es
+    push    di
+    push    ds
+    push    si
+    push    cx
+    push    ax
+    
+    mov     es,     bx
+    
+    mov     si,     offset _scratch
+    xor     di,     di
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    pop     ax
+    pop     cx
+    pop     si
+    pop     ds
+    pop     di
+    pop     es
+
+.L2:
+
+    xor     dx,     dx
+    dec     ax
+    mov     cs:[_history_idx],      ax
+    
+    push    cx
+    
+    mov     cx,     2
+    mul     cx
+    
+    pop     cx
+    push    es
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_history]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    pop     es
+    
+    mov     ds,     ax
+    xor     si,     si
+
+.L4:
+
+    and     ch,     ch
+    jz      .L5
+    
+    xor     ah,     ah
+    mov     al,     [_curr_col]
+    
+    push    cx
+    push    dx
+    xor     dx,     dx
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    add     ax,     cx
+    
+    mov     cx,     HEX (50)
+    div     cx
+    
+    xchg    ax,     dx
+    pop     dx
+    pop     cx
+    
+    and     ax,     ax
+    jnz     .L6
+    
+    push    ax
+    push    bx
+    push    dx
+    push    cx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    pop     cx
+    dec     dh
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (50)
+    int     HEX (10)
+    
+    mov     byte ptr es:[di],       0
+    call    _erase_char
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (4F)
+    int     HEX (10)
+    
+    pop     dx
+    pop     bx
+    pop     ax
+    
+    dec     ch
+    dec     di
+    
+    jmp     short   .L4
+
+.L6:
+
+    mov     byte ptr es:[di],       0
+    call    _erase_char
+    
+    dec     ch
+    dec     di
+    
+    jmp     short   .L4
+
+.L5:
+
+    lodsb
+    
+    or      al,     al
+    jz      .L1
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    stosb
+    inc     ch
+    
+    jmp     short   .L5
+
+.L1:
+
+    mov     ax,     ds
+    
+    and     ax,     ax
+    jz      .L3
+    
+    cmp     ax,     cs:[_curr_scratch]
+    jne     .L3
+    
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    xor     ax,     ax
+    mov     cs:[_curr_scratch],     ax
+
+.L3:
+
+    pop     bx
+    pop     ds
+    pop     es
+    
+    ret
diff --git a/src/apps/pcomm/pcomm.asm b/src/apps/pcomm/pcomm.asm
new file mode 100644 (file)
index 0000000..c9c2a41
--- /dev/null
@@ -0,0 +1,994 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            pcomm.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _main
+;******************************************************************************
+global      _main
+_main:
+
+    mov     ax,     HEX (2523)
+    mov     dx,     offset _cbreak_handler
+    int     HEX (21)
+    
+    mov     bx,     offset _welcome_message
+    call    _writestr
+
+.L5:
+
+    mov     ah,     HEX (19)
+    int     HEX (21)
+    
+    mov     cs:[_curr_drive],   al
+
+.L6:
+
+    mov     si,     offset _curr_path
+    xor     dl,     dl                                                          ; Default/Current directory.
+    
+    mov     ah,     HEX (47)
+    int     HEX (21)
+
+.L7:
+
+    call    _prompt
+    
+    mov     cl,     cs:[_scratch_size]
+    xor     ch,     ch
+    
+    mov     ax,     cs:[_vec_history + 4]
+    mov     cs:[_history_idx],      ax
+    
+    mov     di,     offset _scratch
+
+.L11:
+
+    mov     ah,     HEX (08)
+    int     HEX (21)
+    
+    and     al,     al
+    jnz     .L10
+    
+    mov     ah,     HEX (08)
+    int     HEX (21)
+    
+    cmp     al,     HEX (48)
+    je      .L1
+    
+    cmp     al,     HEX (4B)
+    je      .L4
+    
+    cmp     al,     HEX (50)
+    je      .L2
+    
+    jmp     .L11
+
+.L10:
+
+    cmp     al,     HEX (09)
+    jne     .L14
+    
+    push    ax
+    push    cx
+    push    dx
+    
+    xor     ah,     ah
+    mov     al,     ch
+    xor     dx,     dx
+    
+    mov     cx,     4
+    div     cx
+    
+    mov     cx,     4
+    sub     cx,     dx
+    
+    mov     al,     ' '
+    push    cx
+
+.L15:
+
+    and     cx,     cx
+    jz      .L16
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    stosb
+    dec     cx
+    
+    jmp     .L15
+
+.L16:
+
+    pop     ax
+    pop     dx
+    pop     cx
+    
+    add     ch,     al
+    pop     ax
+    
+    jmp     .L11
+
+.L14:
+
+    cmp     al,     HEX (0D)
+    je      .L3
+    
+    cmp     al,     HEX (08)
+    je      .L4
+    
+    cmp     ch,     cl
+    jae     .L11
+    
+    cmp     al,     HEX (20)
+    jb      .L11
+    
+    cmp     al,     HEX (7F)
+    ja      .L11
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    stosb
+    inc     ch
+    
+    jmp     .L11
+
+.L4:
+
+   call _handle_backspace
+   jmp  .L11 
+
+.L3:
+
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0A)
+    int     HEX (21)
+    
+    and     ch,     ch
+    jz      .L7
+    
+    xor     ah,     ah
+    mov     al,     ch
+    
+    xor     dx,     dx
+    inc     ax
+    
+    push    ax
+    push    dx
+    
+    call    _malloc
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      .L20
+    
+    push    es
+    push    di
+    push    ds
+    push    si
+    push    cx
+    push    bx
+    
+    mov     es,     ax
+    push    es
+    
+    mov     bx,     offset _vec_history
+    push    bx
+    
+    call    _vec_push
+    add     sp,     4
+    
+    mov     si,     offset _scratch
+    xor     di,     di
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    pop     bx
+    pop     cx
+    pop     si
+    pop     ds
+    pop     di
+    pop     es
+
+.L20:
+
+    cmp     ch,     2
+    jne     .L21
+    
+    mov     si,     offset _scratch
+    
+    cmp     byte ptr [si + 1],      ':'
+    jne     .L21
+    
+    xor     ah,     ah
+    mov     al,     [si]
+    
+    push    ax
+    
+    call    _isalpha
+    add     sp,     2
+    
+    and     ax,     ax
+    jz      .L7
+    
+    xor     ah,     ah
+    mov     al,     [si]
+    
+    push    ax
+    
+    call    _toupper
+    add     sp,     2
+
+.L22:
+
+    sub     al,     HEX (41)
+    mov     dl,     al
+    
+    mov     ah,     HEX (0E)
+    int     HEX (21)
+    
+    jmp     .L5
+
+.L21:
+
+    call    _get_command
+    jc      .L23
+    
+    mov     si,     bx
+    xor     ax,     ax
+    
+    push    bx
+    xor     bx,     bx
+    
+    lodsb
+    
+    or      al,     al
+    jz      .L7
+    
+    or      al,     HEX (20)
+    mov     bl,     al
+
+.L28:
+
+    lodsb
+    
+    or      al,     al
+    jz      .L31
+    
+    mov     cl,     5
+    rol     bx,     cl
+    
+    or      al,     HEX (20)
+    xor     bx,     ax
+    
+    jmp     .L28
+
+.L31:
+
+    mov     di,     bx
+    pop     bx
+    
+    mov     si,     offset _cmd_table
+    mov     cx,     offset _cmd_count
+
+.L29:
+
+    lodsw
+    
+    cmp     di,     ax
+    je      .L30
+    
+    lodsw
+    lodsw
+    loop    .L29
+    
+    jmp     .L23
+
+.L30:
+
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    add     bx,     ax
+    inc     bx
+
+.L33:
+
+    cmp     byte ptr [bx],      0
+    je      .L32
+    
+    cmp     byte ptr [bx],      ' '
+    ja      .L32
+    
+    inc     bx
+    jmp     .L33
+
+.L32:
+
+    lodsw
+    
+    call    cs:[si]
+    jmp     .L5
+
+.L23:
+
+    mov     di,     offset _app_path
+    
+    mov     ax,     '\\'
+    push    ax
+    
+    mov     si,     bx
+    push    bx
+    
+    call    _strrchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      .L27
+    
+    mov     bx,     ax
+    mov     byte ptr [bx],      0
+    
+    call    _format_path
+    
+    mov     al,     '\\'
+    stosb
+    
+    inc     bx
+
+.L27:
+
+    mov     ax,     '.'
+    push    ax
+    
+    mov     si,     bx
+    push    bx
+    
+    call    _strrchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jnz     .L24
+
+.L26:
+
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    add     bx,     ax
+    
+    mov     al,     '.'
+    stosb
+    
+    mov     al,     'c'
+    stosb
+    
+    mov     al,     'o'
+    stosb
+    
+    mov     al,     'm'
+    stosb
+    
+    jmp     .L25
+
+.L24:
+
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    add     bx,     ax
+
+.L25:
+
+    xor     al,     al
+    stosb
+    
+    mov     dx,     offset _app_path
+    
+    add     bx,     1
+    mov     di,     bx
+    
+    mov     bx,     offset _param_blk
+    
+    mov     word ptr [bx + 2],      di
+    mov     word ptr [bx + 4],      ds
+    
+    mov     ax,     HEX (4B00)
+    int     HEX (21)
+    jnc     .L5
+    
+    jmp     .L5
+
+.L1:
+
+    call    _history_up
+    jmp     .L11
+
+.L2:
+
+    call    _history_down
+    jmp     .L11
+
+;******************************************************************************
+; @function         _format_path
+;******************************************************************************
+_format_path:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     dx,     di
+    jmp     short   _format_path.loop
+
+_format_path.store:
+
+    stosb
+    
+    cmp     al,     '\\'
+    jne     _format_path.loop
+
+_format_path.skip:
+
+    lodsb
+    
+    cmp     al,     '\\'
+    je      _format_path.skip
+    
+    dec     si
+
+_format_path.loop:
+
+    mov     ax,     di
+    sub     ax,     dx
+    
+    cmp     ax,     250
+    ja      _format_path.done
+    
+    lodsb
+    
+    and     al,     al
+    jz      _format_path.done
+    
+    cmp     al,     127
+    ja      _format_path.done
+    
+    cmp     al,     32
+    jb      _format_path.done
+    
+    jmp     short   _format_path.store
+
+_format_path.done:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _get_command
+;******************************************************************************
+_get_command:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    si
+    push    ax
+    push    dx
+    
+    mov     word ptr [bp - 2],      0
+    mov     si,     offset _scratch
+
+_get_command.loop:
+
+    lodsb
+    
+    and     al,     al
+    jz      _get_command.done
+    
+    cmp     al,     ' '
+    jbe     _get_command.null
+    
+    cmp     al,     ':'
+    je      _get_command.not_internal
+    
+    cmp     al,     '\\'
+    je      _get_command.not_internal
+    
+    cmp     al,     '.'
+    je      _get_command.not_internal
+
+_get_command.check:
+
+    xor     ah,     ah
+    
+    mov     dx,     ax
+    push    dx
+    
+    call    _isalpha
+    add     sp,     2
+    
+    and     ax,     ax
+    jz      _get_command.loop
+    
+    push    dx
+    
+    call    _tolower
+    add     sp,     2
+    
+    mov     [si - 1],   al
+    jmp     _get_command.loop
+
+_get_command.not_internal:
+
+    mov     word ptr [bp - 2],      1
+    jmp     _get_command.loop
+
+_get_command.null:
+
+    mov     byte ptr [si - 1],      0
+
+_get_command.done:
+
+    mov     bx,     word ptr [bp - 2]
+    
+    pop     dx
+    pop     ax
+    pop     si
+    pop     bp
+    
+    add     sp,     2
+    clc
+    
+    and     bx,     bx
+    jz      _get_command.ret
+    
+    stc
+
+_get_command.ret:
+
+    mov     bx,     offset _scratch
+    ret
+
+;******************************************************************************
+; @function         _handle_backspace
+;******************************************************************************
+_handle_backspace:
+
+    and     ch,     ch
+    jz      .L12
+    
+    xor     ah,     ah
+    mov     al,     cs:[_curr_col]
+    
+    push    cx
+    push    dx
+    xor     dx,     dx
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    add     ax,     cx
+    
+    mov     cx,     HEX (50)
+    div     cx
+    
+    xchg    ax,     dx
+    pop     dx
+    pop     cx
+    
+    and     ax,     ax
+    jnz     .L13
+    
+    push    ax
+    push    bx
+    push    dx
+    push    cx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    pop     cx
+    dec     dh
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (50)
+    int     HEX (10)
+    
+    call    _erase_char
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (4F)
+    int     HEX (10)
+    
+    pop     dx
+    pop     bx
+    pop     ax
+    
+    dec     ch
+    dec     di
+    
+    mov     byte ptr es:[di],       0
+    ret
+
+.L13:
+
+    call    _erase_char
+    
+    dec     ch
+    dec     di
+    
+    mov     byte ptr es:[di],       0
+
+.L12:
+
+    ret
+
+;******************************************************************************
+; @function         _handler_cd
+;******************************************************************************
+_handler_cd:
+
+    push    ax
+    push    bx
+    push    si
+    
+    mov     ax,     ' '
+    push    ax
+    
+    mov     si,     bx
+    push    si
+    
+    call    _strchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      _handler_cd.change
+    
+    mov     bx,     ax
+    mov     byte ptr [bx],      0
+    
+    inc     bx
+
+_handler_cd.skip:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_cd.change
+    
+    cmp     byte ptr [bx],      ' '
+    ja      _handler_cd.error
+    
+    inc     bx
+    jmp     _handler_cd.skip
+
+_handler_cd.change:
+
+    mov     ah,     HEX (3B)
+    mov     dx,     si
+    int     HEX (21)
+    
+    jmp     _handler_cd.done
+
+_handler_cd.error:
+
+    mov     bx,     offset _handler_cd.errmsg
+    call    _writestr
+
+_handler_cd.done:
+
+    pop     si
+    pop     bx
+    pop     ax
+    ret
+
+_handler_cd.errmsg:             db      "cd: too many arguments",   HEX (0D),   HEX (0A),   HEX (00)
+
+;******************************************************************************
+; @function         _handler_cls
+;******************************************************************************
+_handler_cls:
+
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    xor     cx,     cx
+    mov     dx,     HEX (184F)
+    int     HEX (10)
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    xor     dx,     dx
+    int     HEX (10)
+    
+    ret
+
+;******************************************************************************
+; @function         _handler_echo
+;******************************************************************************
+_handler_echo:
+
+    call    _writestr
+    call    _crlf
+    
+    ret
+
+;******************************************************************************
+; @function          _handler_help
+;******************************************************************************
+_handler_help:
+
+    push    ax
+    push    bx
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _handler_help.msg
+    call    _writestr
+
+_handler_help.done:
+
+    pop     ds
+    pop     bx
+    pop     ax
+    ret
+
+_handler_help.msg:
+
+    db      "CD         Change the current directory to the specified path.",               HEX (0D),   HEX (0A)
+    db      "CLS        Clears the screen.",                                                HEX (0D),   HEX (0A)
+    db      "DATE       Displays the system date.",                                         HEX (0D),   HEX (0A)
+    db      "DIR        Displays a list of files and subdirectories in a directory.",       HEX (0D),   HEX (0A)
+    db      "ECHO       Specifies the text to display to the screen.",                      HEX (0D),   HEX (0A)
+    db      "EXIT       Exit the current shell if it's not the last instance.",             HEX (0D),   HEX (0A)
+    db      "REBOOT     Reboots the machine.",                                              HEX (0D),   HEX (0A)
+    db      "TIME       Displays the system time.",                                         HEX (0D),   HEX (0A)
+    db      "TYPE       Displays the contents of a text file.",                             HEX (0D),   HEX (0A)
+    
+    db      HEX (00)
+
+;******************************************************************************
+; @function         _handler_reboot
+;******************************************************************************
+_handler_reboot:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Stop floppy motor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     HEX (03F2)
+    xor     al,     al
+    out     dx,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cold reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     bx,     HEX (0472)
+    mov     word ptr es:[bx],   0
+    
+    jmp     HEX (F000) : HEX (FFF0)
+
+;******************************************************************************
+; @function         _prompt
+;******************************************************************************
+global      _prompt
+_prompt:
+
+    push    ax
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+
+.L19:
+
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    mov     cs:[_curr_row],     dh          ; byte ptr [bp - 2]
+    mov     cs:[_curr_col],     dl          ; byte ptr [bp - 1]
+
+.L17:
+
+    mov     di,     offset _scratch
+    xor     al,     al
+    
+    mov     cl,     cs:[_scratch_size]
+    xor     ch,     ch
+    
+    rep     stosb
+    
+    xor     al,     al
+    mov     cs:[_scratch_len],      al
+    
+    mov     al,     cs:[_curr_drive]
+    add     al,     'A'
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ':'
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '\\'
+    int     HEX (21)
+
+.L8:
+
+    mov     bx,     offset _curr_path
+    call    _writestr
+
+.L9:
+
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '>'
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ' '
+    int     HEX (21)
+
+.L18:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "ver.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; int21/ah=0A variables.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_scratch_size:                  db      255
+_scratch_len:                   db      0
+
+global      _scratch
+_scratch:                       db      257     dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Variables for executing application.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;_formatted_cmd:                 db      255     dup (0)
+_app_path:                      db      255     dup (0)
+_param_blk:                     db      16      dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _vec_history
+_vec_history:                   db      6       dup (0)
+
+global      _curr_row
+_curr_row:                      db      HEX (00)
+
+global      _curr_col
+_curr_col:                      db      HEX (00)
+
+global      _history_idx
+_history_idx:                   dw      HEX (0000)
+
+global      _curr_scratch
+_curr_scratch:                  dw      HEX (0000)
+
+_curr_path:                     db      65      dup (0)
+_curr_drive:                    db      HEX (00)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Commands.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "cmdhash.gen"
+_cmd_size:                      equ     6
+
+align   4
+_cmd_table:
+
+    dw      hash_cd
+    dw      0
+    dw      _handler_cd
+    
+    dw      hash_cls
+    dw      0
+    dw      _handler_cls
+    
+    dw      hash_date
+    dw      0
+    dw      _handler_date
+    
+    dw      hash_dir
+    dw      0
+    dw      _handler_dir
+    
+    dw      hash_echo
+    dw      0
+    dw      _handler_echo
+    
+    dw      hash_exit
+    dw      0
+    dw      _handler_exit
+    
+    dw      hash_help
+    dw      0
+    dw      _handler_help
+    
+    dw      hash_reboot
+    dw      0
+    dw      _handler_reboot
+    
+    dw      hash_time
+    dw      0
+    dw      _handler_time
+    
+    dw      hash_type
+    dw      0
+    dw      _handler_type
+
+_cmd_count:                     equ     ($ - _cmd_table) / _cmd_size
diff --git a/src/apps/pcomm/time.asm b/src/apps/pcomm/time.asm
new file mode 100644 (file)
index 0000000..51fe65d
--- /dev/null
@@ -0,0 +1,87 @@
+;******************************************************************************
+; @file             time.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _handler_time
+;******************************************************************************
+global      _handler_time
+_handler_time:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ah,     HEX (2C)
+    int     HEX (21)
+    mov     bx,     dx
+    
+    cmp     ch,     10
+    jae     _handler_time.got_hour
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '0'
+    int     HEX (21)
+
+_handler_time.got_hour:
+
+    xor     ah,     ah
+    mov     al,     ch
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ':'
+    int     HEX (21)
+    
+    cmp     cl,     10
+    jae     _handler_time.got_minute
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '0'
+    int     HEX (21)
+
+_handler_time.got_minute:
+
+    xor     ah,     ah
+    mov     al,     cl
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     ':'
+    int     HEX (21)
+    
+    cmp     bh,     10
+    jae     _handler_time.got_second
+    
+    mov     ah,     HEX (02)
+    mov     dl,     '0'
+    int     HEX (21)
+
+_handler_time.got_second:
+
+    xor     ah,     ah
+    mov     al,     bh
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0A)
+    int     HEX (21)
+
+_handler_time.done:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/pcomm/type.asm b/src/apps/pcomm/type.asm
new file mode 100644 (file)
index 0000000..57197f2
--- /dev/null
@@ -0,0 +1,219 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            type.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _handler_type
+;******************************************************************************
+global      _handler_type
+_handler_type:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     4
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 2],      0
+    
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     di,     offset _cmdline
+    mov     si,     bx
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    mov     bx,     offset _cmdline
+
+_handler_type.store_file:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_type.next
+    
+    mov     si,     bx
+    push    si
+    
+    mov     ax,     offset _vec_files
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+
+_handler_type.check:
+
+    mov     ax,     ' '
+    push    ax
+    
+    mov     si,     bx
+    push    si
+    
+    call    _strchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      _handler_type.next
+    
+    mov     bx,     ax
+    mov     byte ptr [bx],      0
+    
+    inc     bx
+
+_handler_type.skip:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_type.next
+    
+    cmp     byte ptr [bx],      ' '
+    ja      _handler_type.store_file
+    
+    inc     bx
+    jmp     _handler_type.skip
+
+_handler_type.next:
+
+    mov     ax,     word ptr [bp - 4]
+    inc     ax
+    
+    cmp     ax,     cs:[_vec_files + 4]
+    ja      _handler_type.cleanup
+    
+    mov     word ptr [bp - 4],      ax
+    dec     ax
+    
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    push    es
+    
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     bx,     ax
+    
+    pop     es
+
+_handler_type.open:
+
+    mov     ax,     HEX (3D02)
+    mov     dx,     bx
+    int     HEX (21)
+    jc      _handler_type.cleanup
+    
+    mov     bx,     ax
+
+_handler_type.clear_and_read:
+
+    mov     di,     offset _buffer
+    xor     al,     al
+    
+    mov     cx,     256
+    rep     stosb
+    
+    mov     ah,     HEX (3F)
+    mov     cx,     255
+    mov     dx,     offset _buffer
+    int     HEX (21)
+    jc      _handler_type.close
+    
+    and     ax,     ax
+    jz      _handler_type.close
+    
+    mov     si,     offset _buffer
+
+_handler_type.print_loop:
+
+    lodsb
+    
+    and     al,     al
+    jz      _handler_type.clear_and_read
+    
+    cmp     al,     HEX (0A)
+    jne     _handler_type.char_ok
+    
+    push    ax
+    
+    mov     ah,     HEX (02)
+    mov     dl,     HEX (0D)
+    int     HEX (21)
+    
+    pop     ax
+
+_handler_type.char_ok:
+
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    jmp     _handler_type.print_loop
+
+_handler_type.close:
+
+    mov     ah,     HEX (3E)
+    int     HEX (21)
+    
+    jmp     _handler_type.next
+
+_handler_type.cleanup:
+
+    mov     ax,     cs:[_vec_files + 0]
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     di,     offset _vec_files
+    xor     al,     al
+    
+    mov     cx,     6
+    rep     stosb
+
+_handler_type.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     4
+    pop     bp
+    
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_vec_files:                     db      6       dup (0)
+
+_cmdline:                       db      256     dup (0)
+_buffer:                        db      256     dup (0)
+
diff --git a/src/apps/pcomm/vector.asm b/src/apps/pcomm/vector.asm
new file mode 100644 (file)
index 0000000..9f89487
--- /dev/null
@@ -0,0 +1,142 @@
+;******************************************************************************
+; @file             vector.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _vec_adjust
+;******************************************************************************
+_vec_adjust:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_adjust.check:
+
+    mov     cx,     [bx + 2]
+    
+    cmp     cx,     word ptr [bp + 6]
+    ja      _vec_adjust.done
+
+_vec_adjust.check2:
+
+    and     cx,     cx
+    jnz     _vec_adjust.shift
+    
+    mov     cx,     16
+    jmp     short   _vec_adjust.set
+
+_vec_adjust.shift:
+
+    shl     cx
+
+_vec_adjust.set:
+
+    mov     [bx + 2],   cx
+
+_vec_adjust.alloc:
+
+    mov     ax,     2
+    xor     dx,     dx
+    
+    mul     cx
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     [bx + 0]
+    push    ax
+    
+    call    _realloc
+    add     sp,     6
+    
+    mov     [bx + 0],       ax
+
+_vec_adjust.done:
+
+    xor     ax,     ax
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _vec_push
+;******************************************************************************
+global      _vec_push
+_vec_push:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_push.alt:
+
+    mov     ax,     [bx + 4]
+    push    ax
+    
+    push    word ptr [bp + 4]
+    
+    call    _vec_adjust
+    add     sp,     4
+    
+    mov     word ptr [bp - 2],      ax
+    
+    and     ax,     ax
+    jnz     _vec_push.done
+
+_vec_push.set:
+
+    mov     ax,     [bx + 0]
+    mov     es,     ax
+    
+    mov     ax,     [bx + 4]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     di,     ax
+    
+    mov     ax,     [bp + 6]
+    mov     es:[di],    ax
+    
+    mov     cx,     [bx + 4]
+    add     cx,     1
+    
+    mov     [bx + 4],   cx
+
+_vec_push.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    pop     bp
+    
+    ret
diff --git a/src/apps/pcomm/writechr.asm b/src/apps/pcomm/writechr.asm
new file mode 100644 (file)
index 0000000..b268990
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             writechr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         writechr
+;******************************************************************************
+global      _writechr
+_writechr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    bp                                                                  ; Some BIOSes destroy BP when the screen scrolls
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/apps/pcomm/writedec.asm b/src/apps/pcomm/writedec.asm
new file mode 100644 (file)
index 0000000..4b0402d
--- /dev/null
@@ -0,0 +1,54 @@
+;******************************************************************************
+; @file             writedec.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writedec
+;******************************************************************************
+global      _writedec
+_writedec:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    bp
+    
+    mov     bx,     10
+    xor     cx,     cx
+
+_writedec.cloop:
+
+    div     bx
+    inc     cx
+    
+    push    dx
+    xor     dx,     dx
+    
+    and     ax,     ax
+    jnz     _writedec.cloop
+
+_writedec.dloop:
+
+    pop     ax
+    add     al,     '0'
+    
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    loop    _writedec.dloop
+
+_writedec.done:
+
+    pop     bp
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/pcomm/writehex.asm b/src/apps/pcomm/writehex.asm
new file mode 100644 (file)
index 0000000..dd07263
--- /dev/null
@@ -0,0 +1,58 @@
+;******************************************************************************
+; @file             writehex.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+global      _writehex
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     4
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+    
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/apps/pcomm/writestr.asm b/src/apps/pcomm/writestr.asm
new file mode 100644 (file)
index 0000000..161b82e
--- /dev/null
@@ -0,0 +1,75 @@
+;******************************************************************************
+; @file             writestr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _writestr
+;******************************************************************************
+global      _writestr
+_writestr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    si
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize si with bx
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump over our printing code to get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _writestr.next
+
+_writestr.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (02)
+    mov     dl,     al
+    int     HEX (21)
+
+_writestr.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _writestr.print
+
+_writestr.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     si
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/apps/pcomm/xmalloc.asm b/src/apps/pcomm/xmalloc.asm
new file mode 100644 (file)
index 0000000..5957544
--- /dev/null
@@ -0,0 +1,90 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            xmalloc.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @function        _xmalloc
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _xmalloc
+_xmalloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    es
+    push    cx
+    push    di
+    
+    push    word ptr [bp + 6]
+    push    word ptr [bp + 4]
+    
+    call    _malloc
+    add     sp,     4
+    
+    and     ax,     ax
+    jnz     _xmalloc.ok
+    
+    pop     ax
+    pop     di
+    pop     cx
+    pop     es
+    pop     bp
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _err_malloc
+    call    _writestr
+    
+    mov     ax,     HEX (4C01)
+    int     HEX (21)
+
+_xmalloc.ok:
+
+    push    ax
+    push    bx
+    
+    dec     ax
+    mov     es,     ax
+    
+    xor     bx,     bx
+    mov     cx,     es:[bx + 3]
+    
+    pop     bx
+    pop     ax
+    
+    push    ax
+    mov     es,     ax
+
+_xmalloc.loop:
+
+    xor     di,     di
+    
+    push    ax
+    push    cx
+    
+    xor     al,     al
+    mov     cx,     16
+    rep     stosb
+    
+    pop     cx
+    pop     ax
+    
+    inc     ax
+    mov     es,     ax
+    
+    loop    _xmalloc.loop
+
+_xmalloc.done:
+
+    pop     ax
+    pop     di
+    pop     cx
+    pop     es
+    pop     bp
+    ret
+
+_err_malloc:                    db      "Memory full (malloc)",     HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/apps/pcomm/xstrcpy.asm b/src/apps/pcomm/xstrcpy.asm
new file mode 100644 (file)
index 0000000..77c9b06
--- /dev/null
@@ -0,0 +1,53 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            xstrcpy.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @function        _xstrcpy
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _xstrcpy
+_xstrcpy:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    ax
+    push    si
+    push    di
+    
+    mov     si,     [bp + 6]
+    mov     di,     [bp + 4]
+
+_xstrcpy.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _xstrcpy.done
+    
+    cmp     al,     90
+    ja      _xstrcpy.got_char
+    
+    cmp     al,     65
+    jb      _xstrcpy.got_char
+    
+    or      al,     HEX (20)
+
+_xstrcpy.got_char:
+
+    stosb
+    jmp     short   _xstrcpy.loop
+
+_xstrcpy.done:
+
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     si
+    pop     ax
+    pop     bp
+    ret
diff --git a/src/boot/Makefile.unix b/src/boot/Makefile.unix
new file mode 100644 (file)
index 0000000..308b6fd
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  mbr freeldr
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for t in $(TARGETS); do \
+         if [ ! -d "$(OBJDIR)/$$t" ]; then mkdir -p "$(OBJDIR)/$$t"; fi; \
+         $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" all; \
+       done
+
+clean:
+       for t in $(TARGETS); do \
+         if [ -d "$(OBJDIR)/$$t" ]; then \
+           $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" clean; \
+         fi; \
+       done
diff --git a/src/boot/Makefile.w32 b/src/boot/Makefile.w32
new file mode 100644 (file)
index 0000000..48a3baa
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  mbr freeldr
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%t in ($(TARGETS)) do ( \
+               ( if not exist "$(OBJDIR)/%%t" ( mkdir "$(OBJDIR)/%%t" ) ) & \
+               $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" all \
+       )
+
+clean:
+       for %%t in ($(TARGETS)) do ( \
+               if exist "$(OBJDIR)/%%t" ( \
+                       $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" clean \
+               ) \
+       )
diff --git a/src/boot/freeldr/Makefile.unix b/src/boot/freeldr/Makefile.unix
new file mode 100644 (file)
index 0000000..19e4d5d
--- /dev/null
@@ -0,0 +1,40 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  bootsect libc core
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: kwdhash.gen
+       for t in $(TARGETS); do \
+               if [ ! -d "$(OBJDIR)/$$t" ]; then mkdir -p "$(OBJDIR)/$$t"; fi; \
+               $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" all; \
+       done
+
+clean:
+       if [ -f kwdhash.gen ]; then rm -rf kwdhash.gen; fi
+       if [ -f genhash.exe ]; then rm -rf genhash.exe; fi
+       if [ -f genhash ]; then rm -rf genhash; fi
+
+       for t in $(TARGETS); do \
+               if [ -d "$(OBJDIR)/$$t" ]; then \
+                       $(MAKE) -C "$(OBJDIR)/$$t" -f "$(SRCDIR)/$$t/Makefile.unix" OBJDIR="$(OBJDIR)/$$t" SRCDIR="$(SRCDIR)/$$t" clean; \
+               fi; \
+       done
+
+ifeq ($(OS), Windows_NT)
+kwdhash.gen: keywords genhash.exe
+       ./genhash.exe < $< > $@
+
+genhash.exe: genhash.c
+       gcc -o $@ $^
+else
+kwdhash.gen: keywords genhash
+       ./genhash < $< > $@
+
+genhash: genhash.c
+       gcc -o $@ $^
+endif
diff --git a/src/boot/freeldr/Makefile.w32 b/src/boot/freeldr/Makefile.w32
new file mode 100644 (file)
index 0000000..849742c
--- /dev/null
@@ -0,0 +1,32 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  bootsect libc core
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: kwdhash.gen
+       for %%t in ($(TARGETS)) do ( \
+               ( if not exist "$(OBJDIR)/%%t" ( mkdir "$(OBJDIR)/%%t" ) ) & \
+               $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" all \
+       )
+
+clean:
+       if exist kwdhash.gen ( del /q kwdhash.gen )
+       if exist genhash.exe ( del /q genhash.exe )
+       if exist genhash ( del /q genhash )
+
+       for %%t in ($(TARGETS)) do ( \
+               if exist "$(OBJDIR)/%%t" ( \
+                       $(MAKE) -C "$(OBJDIR)/%%t" -f "$(SRCDIR)/%%t/Makefile.w32" OBJDIR="$(OBJDIR)/%%t" SRCDIR="$(SRCDIR)/%%t" clean \
+               ) \
+       )
+
+kwdhash.gen: keywords genhash.exe
+       genhash.exe < $< > $@
+
+genhash.exe: genhash.c
+       gcc -o $@ $^
diff --git a/src/boot/freeldr/bootsect/Makefile.unix b/src/boot/freeldr/bootsect/Makefile.unix
new file mode 100644 (file)
index 0000000..01c86d7
--- /dev/null
@@ -0,0 +1,28 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: fat12.bin fat16.bin fat32_chs.bin
+
+clean:
+       if [ -f fat12.bin ]; then rm -rf fat12.bin; fi
+       if [ -f fat12.lst ]; then rm -rf fat12.lst; fi
+
+       if [ -f fat16.bin ]; then rm -rf fat16.bin; fi
+       if [ -f fat16.lst ]; then rm -rf fat16.lst; fi
+
+       if [ -f fat32_chs.bin ]; then rm -rf fat32_chs.bin; fi
+       if [ -f fat32_chs.lst ]; then rm -rf fat32_chs.lst; fi
+
+fat12.bin: oldfat.asm
+       ../../../utils/binutils/sasm -D__FAT12__ -f bin -l fat12.lst -o $@ $<
+
+fat16.bin: oldfat.asm
+       ../../../utils/binutils/sasm -D__FAT16__ -f bin -l fat16.lst -o $@ $<
+
+fat32_chs.bin: fat32_chs.asm
+       ../../../utils/binutils/sasm -f bin -l fat32_chs.lst -o $@ $<
diff --git a/src/boot/freeldr/bootsect/Makefile.w32 b/src/boot/freeldr/bootsect/Makefile.w32
new file mode 100644 (file)
index 0000000..73b2aaf
--- /dev/null
@@ -0,0 +1,28 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: fat12.bin fat16.bin fat32_chs.bin
+
+clean:
+       if exist fat12.bin ( del /q fat12.bin )
+       if exist fat12.lst ( del /q fat12.lst )
+
+       if exist fat16.bin ( del /q fat16.bin )
+       if exist fat16.lst ( del /q fat16.lst )
+
+       if exist fat32_chs.bin ( del /q fat32_chs.bin )
+       if exist fat32_chs.lst ( del /q fat32_chs.lst )
+
+fat12.bin: oldfat.asm
+       ../../../utils/binutils/sasm -D__FAT12__ -f bin -l fat12.lst -o $@ $<
+
+fat16.bin: oldfat.asm
+       ../../../utils/binutils/sasm -D__FAT16__ -f bin -l fat16.lst -o $@ $<
+
+fat32_chs.bin: fat32_chs.asm
+       ../../../utils/binutils/sasm -f bin -l fat32_chs.lst -o $@ $<
diff --git a/src/boot/freeldr/bootsect/fat32_chs.asm b/src/boot/freeldr/bootsect/fat32_chs.asm
new file mode 100644 (file)
index 0000000..39796b0
--- /dev/null
@@ -0,0 +1,535 @@
+;******************************************************************************
+; @file             fat32_chs.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Memory layout.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Mem.Stage1:                     equ     HEX (7C00)
+Mem.Stage2:                     equ     HEX (0600)
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    jmp     short   _after_bpb
+    nop
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; System Identifier.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;system_id:                      db      HEX (08)    dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; BIOS Parameter Block.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;bytes_per_sector:               dw      HEX (0000)
+;sectors_per_cluster:            db      HEX (00)
+;reserved_sectors:               dw      HEX (0000)
+;number_of_fats:                 db      HEX (00)
+;root_entries:                   dw      HEX (0000)
+;total_sectors16:                dw      HEX (0000)
+;media_descriptor:               db      HEX (00)
+;sectors_per_fat:                dw      HEX (0000)
+;sectors_per_track:              dw      HEX (0000)
+;heads_per_cylinder:             dw      HEX (0000)
+;hidden_sectors:                 dw      HEX (0000),     HEX (0000)
+;total_sectors32:                dw      HEX (0000),     HEX (0000)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Extended BIOS Parameter Block.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;sectors_per_fat32:              dw      HEX (0000),     HEX (0000)
+;flags:                          dw      HEX (0000)
+;version:                        dw      HEX (0000)
+;root_cluster:                   dw      HEX (0000),     HEX (0000)
+;info_sector:                    dw      HEX (0000)
+;backup_boot:                    dw      HEX (0000)
+;reserved2:                      dw      6       dup (0)
+;drive_no:                       db      HEX (00)
+;boot_flags:                     db      HEX (00)
+;ext_boot_sign:                  db      HEX (00)
+;volume_id:                      dw      HEX (0000),     HEX (0000)
+;volume_label:                   db      HEX (0B)    dup (0)
+;fs_type:                        db      HEX (08)    dup (0)
+
+
+db      HEX (5A) - (. - _start)     dup (0)
+
+%define     _bytes_per_sector           (bp + 11)
+%define     _sectors_per_cluster        (bp + 13)
+%define     _reserved_sectors           (bp + 14)
+%define     _number_of_fats             (bp + 16)
+%define     _sectors_per_track          (bp + 24)
+%define     _heads_per_cylinder         (bp + 26)
+%define     _hidden_sectors             (bp + 28)
+%define     _sectors_per_fat32          (bp + 36)
+%define     _root_cluster               (bp + 44)
+%define     _drive_no                   (bp + 64)
+
+;******************************************************************************
+; @function         _after_bpb
+;******************************************************************************
+_after_bpb:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Far jump to the next instruction to fix the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp    (Mem.Stage1 >> 4) : _real_start
+
+loadseg_60:
+
+    dw      HEX (0000)
+    dw      Mem.Stage2 >> 4
+
+;******************************************************************************
+; @function         _real_start
+;******************************************************************************
+_real_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    cs
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the stack segment and the base and stack pointers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     ss,     ax
+    
+    mov     bp,     Mem.Stage1
+    lea     sp,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no. passed to us from them BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    dl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get drive parameters (HDD only).
+    ;; 
+    ;; If a drive is moved between different systems, its geometry may
+    ;; differ in the eyes of the different BIOSes, more so when it's a
+    ;; disk image for a VM.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (08)                                                    ; clobbers AX, BL, CX, DX, ES:DI
+    int     HEX (13)
+    jc      .calc_offsets
+    
+    and     cx,     HEX (3F)
+    mov     [_sectors_per_track],       cx
+    
+    mov     cl,     dh
+    inc     cx
+    mov     [_heads_per_cylinder],      cx
+    
+    .calc_offsets:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate the offset of the first FAT.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     si,     [_hidden_sectors]
+        mov     di,     [_hidden_sectors + 2]
+        
+        add     si,     [_reserved_sectors]
+        adc     di,     0
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Save the offset ready for the fathelper at the start of
+        ;; freeldr.sys.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     [bp - 24],      si
+        mov     [bp - 22],      di
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate how many sectors both FATs require.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     al,     [_number_of_fats]
+        cbw
+        push    ax
+        
+        mul     word ptr [_sectors_per_fat32 + 2]
+        add     di,     ax
+        
+        pop     ax
+        mul     word ptr [_sectors_per_fat32]
+        
+        add     ax,     si
+        adc     dx,     di
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Save the offset for later use.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     [bp - 20],      ax
+        mov     [bp - 18],      dx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate the sector mask.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     ax,     [_bytes_per_sector]
+        shr     ax
+        shr     ax
+        dec     ax
+        mov     [bp - 16],      ax
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate the sector shift.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        xor     cx,     cx
+        
+        xchg    ax,     cx
+        inc     cx
+    
+    .secshift:
+    
+        inc     ax
+        shr     cx
+        
+        cmp     cx,     1
+        jne     .secshift
+        
+        mov     [bp - 14],      ax
+        dec     cx
+        
+        mov     ax,     [_root_cluster]
+        mov     dx,     [_root_cluster + 2]
+    
+    .ff_next_cluster:
+    
+        push    dx
+        push    ax
+        
+        call    _convert_cluster
+        jnc     .ff_next_sector
+        
+        call    _error
+        db      "NF",       HEX (0D),   HEX (0A),   HEX (00)
+    
+    .ff_next_sector:
+    
+        push    bx
+        les     bx,     [loadseg_60]
+        
+        push    es
+        call    _read_sectors
+        
+        pop     es
+        push    dx
+        push    ax
+        
+        mov     ax,     [_bytes_per_sector]
+    
+    .ff_next_entry:
+    
+        mov     si,     offset Entry.Filename
+        mov     cx,     offset Entry.Filename.Length
+        
+        mov     di,     ax
+        sub     di,     HEX (20)
+        
+        repe    cmpsb
+        jz      .ff_done
+        
+        sub     ax,     HEX (20)
+        jnz     .ff_next_entry
+        
+        pop     ax
+        pop     dx
+        pop     bx
+        
+        dec     bx
+        jnz     .ff_next_sector
+    
+    .ff_find_next_cluster:
+    
+        pop     ax
+        pop     dx
+        
+        call    _next_cluster
+        jmp     short   .ff_next_cluster
+    
+    .ff_done:
+    
+        mov     ax,     es:[di + HEX (1A) - 11]
+        mov     dx,     es:[di + HEX (14) - 11]
+    
+    .c4:
+    
+        sub     bx,     bx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Get the number of sectors per cluster.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        xor     ch,     ch
+        mov     cl,     [_sectors_per_cluster]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Initialize the di register with the value i the cx register.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     si,     cx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Make sure we read at least 4 sectors.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        cmp     si,     4
+        jae     .c5
+        
+        mov     si,     4
+    
+    .c5:
+    
+        push    dx
+        push    ax
+        push    bx
+        
+        call    _convert_cluster
+        jc      .execute
+        
+        mov     di,     bx
+        sub     si,     bx
+        pop     bx
+    
+    .c6:
+    
+        call    _read_sectors
+        
+        dec     di
+        jnz     .c6
+        
+        pop     ax
+        pop     dx
+        
+        and     si,     si
+        jz      .execute
+        
+        call    _next_cluster
+        jmp     short   .c5
+    
+    .execute:
+    
+        mov     cl,     [_drive_no]
+        jmp     far ptr [loadseg_60]
+
+;******************************************************************************
+; @function         _convert_cluster
+;******************************************************************************
+_convert_cluster:
+
+    cmp     dx,     HEX (0FFF)
+    jne     _convert_cluster.c3
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster.c3
+    
+    stc
+    ret
+
+_convert_cluster.c3:
+
+    mov     cx,     dx
+    
+    sub     ax,     2
+    sbb     cx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    xchg    cx,     ax
+    mul     bx
+    
+    xchg    ax,     cx
+    mul     bx
+    
+    add     dx,     cx
+    
+    add     ax,     [bp - 20]
+    add     dx,     [bp - 18]
+    
+    ret
+
+;******************************************************************************
+; @function         _error
+;******************************************************************************
+_error:
+
+    pop     si
+    jmp     short   _error.next
+
+_error.print:
+
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_error.next:
+
+    lodsb
+    
+    and     al,     al
+    jnz     _error.print
+
+_error.done:
+
+    xor     ax,     ax
+    int     HEX (16)
+    int     HEX (19)
+
+;******************************************************************************
+; @function         _next_cluster
+;******************************************************************************
+_next_cluster:
+
+    mov     di,     ax
+    and     di,     [bp - 16]
+    
+    mov     cx,     [bp - 14]
+
+_next_cluster.cn_loop:
+
+    shr     dx
+    rcr     ax
+    loop    _next_cluster.cn_loop
+    
+    shl     di
+    shl     di
+    
+    add     ax,     [bp - 24]
+    adc     dx,     [bp - 22]
+    
+    push    es
+    push    bx
+    
+    ;mov     bx,     (Mem.Stage2 >> 4) - HEX (20)
+    ;mov     es,     bx
+    ;xor     bx,     bx
+    
+    call    _read_sectors
+
+_next_cluster.cn_exit:
+
+    pop     bx
+    pop     es
+    
+    mov     ax,     es:[di]
+    mov     dx,     es:[di + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    div     word ptr [_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA % SPT         = sector - 1
+    
+    xchg    cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr [_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) % HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    
+    ror     ah
+    ror     ah                                                                  ; excess bits of cylinder no. must be 0 anyway
+    
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     [_drive_no]
+    int     HEX (13)
+    jnc     _read_sectors.success                                                   ; CF = 0 if no _error
+
+_read_sectors.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    mov     ax,     [_bytes_per_sector]
+    mov     cl,     4
+    shr     ax,     cl
+    
+    mov     cx,     es
+    add     cx,     ax
+    mov     es,     cx
+
+_read_sectors.no_incr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Entry.Filename:                 db      "FREELDR SYS"
+Entry.Filename.Length:          equ     ($ - Entry.Filename)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pad until 510 bytes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+db      HEX (01FE) - (. - _start)   dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Boot signature.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+dw      HEX (AA55)
diff --git a/src/boot/freeldr/bootsect/oldfat.asm b/src/boot/freeldr/bootsect/oldfat.asm
new file mode 100644 (file)
index 0000000..71ec3a6
--- /dev/null
@@ -0,0 +1,804 @@
+;******************************************************************************
+; @file             oldfat.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Memory layout.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Mem.Stage1:                     equ     HEX (7C00)
+Mem.Stage2:                     equ     HEX (0600)
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    jmp     short   after_bpb
+    nop
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; System Identifier.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;system_id:                      db      HEX (08)    dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; BIOS Parameter Block.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;bytes_per_sector:               dw      HEX (0000)
+;sectors_per_cluster:            db      HEX (00)
+;reserved_sectors:               dw      HEX (0000)
+;number_of_fats:                 db      HEX (00)
+;root_entries:                   dw      HEX (0000)
+;total_sectors16:                dw      HEX (0000)
+;media_descriptor:               db      HEX (00)
+;sectors_per_fat:                dw      HEX (0000)
+;sectors_per_track:              dw      HEX (0000)
+;heads_per_cylinder:             dw      HEX (0000)
+;hidden_sectors:                 dw      HEX (0000),     HEX (0000)
+;total_sectors32:                dw      HEX (0000),     HEX (0000)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Extended BIOS Parameter Block.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;drive_no:                       db      HEX (00)
+;boot_flags:                     db      HEX (00)
+;ext_boot_sign:                  db      HEX (00)
+;volume_id:                      dw      HEX (0000),     HEX (0000)
+;volume_label:                   db      HEX (0B)    dup (0)
+;fs_type:                        db      HEX (08)    dup (0)
+
+
+db      HEX (3E) - (. - _start)     dup (0)
+
+%define     _bytes_per_sector           (bp + 11)
+%define     _sectors_per_cluster        (bp + 13)
+%define     _reserved_sectors           (bp + 14)
+%define     _number_of_fats             (bp + 16)
+%define     _root_entries               (bp + 17)
+%define     _sectors_per_fat            (bp + 22)
+%define     _sectors_per_track          (bp + 24)
+%define     _heads_per_cylinder         (bp + 26)
+%define     _hidden_sectors             (bp + 28)
+%define     _drive_no                   (bp + 36)
+
+;******************************************************************************
+; @function         after_bpb
+;******************************************************************************
+after_bpb:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Far jump to the next instruction to fix the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp    (Mem.Stage1 >> 4) : real_start
+
+;******************************************************************************
+; @function         real_start
+;******************************************************************************
+real_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the stack segment and the base and stack pointers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     ss,     ax
+    
+    mov     bp,     Mem.Stage1
+    lea     sp,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no. passed to us from them BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    dl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get drive parameters (HDD only).
+    ;; 
+    ;; If a drive is moved between different systems, its geometry may
+    ;; differ in the eyes of the different BIOSes, more so when it's a
+    ;; disk image for a VM.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    dl,     HEX (80)
+    jz      .calc_offsets                                                       ; skip if it's a flopy (dl < 80h)
+    
+    mov     ah,     HEX (08)                                                    ; clobbers AX, BL, CX, DX, ES:DI
+    int     HEX (13)
+    jc      .calc_offsets
+    
+    and     cx,     HEX (3F)
+    mov     [_sectors_per_track],       cx
+    
+    mov     cl,     dh
+    inc     cx
+    mov     [_heads_per_cylinder],      cx
+    
+    .calc_offsets:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate the offset of the first FAT.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     si,     [_hidden_sectors]
+        mov     di,     [_hidden_sectors + 2]
+        
+        add     si,     [_reserved_sectors]
+        adc     di,     0
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Save the offset ready for the fathelper at the start of
+        ;; freeldr.sys.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     [bp - 24],      si
+        mov     [bp - 22],      di
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate how many sectors both FATs require.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     al,     [_number_of_fats]
+        cbw
+        mul     word ptr [_sectors_per_fat]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Adjust the FAT offset to get the root directory offset.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        add     si,     ax
+        adc     di,     dx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; As we'll only need the root directory in this file
+        ;; we'll just push the offset to the stack.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        push    si
+        push    di
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Calculate how many sectors the root directory requires.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     ax,     HEX (0020)
+        mul     word ptr [_root_entries]
+        div     word ptr [_bytes_per_sector]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Adjust the root offset to get the data offset.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        add     si,     ax
+        adc     di,     dx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Save the offset for later use.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     [bp - 20],      si
+        mov     [bp - 18],      di
+    
+    .find_stage2:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; The ax register should contain the total amount of sectors
+        ;; of the root directory.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     cx,     ax
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Get the root directory offset off the stack.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        pop     dx
+        pop     ax
+        
+        .find_stage2.read:
+        
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; We'll read the sector into memory 0000:0500.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            mov     bx,     HEX (0050)
+            mov     es,     bx
+            xor     bx,     bx
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Read the root directory in it's entirety.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            push    es
+            push    bx
+            call    _read_sectors
+            
+            pop     bx
+            pop     es
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; The rep cmpsb uses di instead of bx.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            mov     di,     bx
+            mov     dx,     [_root_entries]
+        
+        .find_stage2.compare:
+        
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Save the current offset.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            push    di
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Initialize the si and cx with out entry values.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            mov     si,     offset Entry.Filename
+            mov     cx,     offset Entry.Filename.Length
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Perform the compare.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            repe    cmpsb
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Restore the offset.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            pop     di
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; If the entries match then we've found our entry.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            je      .entry_found
+        
+        .find_stage2.advance:
+        
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Advance to the next offset.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            add     di,     32
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; Decrement the counter.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            dec     dx
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; If we haven't read all th entries then compare this entry.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            jnz     .find_stage2.compare
+            
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            ;; If we reach here we failed to find our entry.
+            ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+            jmp     .error
+    
+    .entry_found:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Check that the entry has the archive bit set.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        test    byte ptr es:[di + 11],      HEX (18)
+        jnz     .error
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Get the starting cluster into the si register.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     ax,     es:[di + 26]
+        mov     dx,     es:[di + 20]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Get the number of sectors per cluster.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        xor     ch,     ch
+        mov     cl,     [_sectors_per_cluster]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Initialize the di register with the value i the cx register.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     di,     cx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Make sure we read at least 4 sectors.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        cmp     di,     4
+        jae     .got_count
+        
+        mov     di,     4
+    
+    .got_count:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; We'll read the sector/cluster into Mem.Stage2.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     bx,     (Mem.Stage2 >> 4)
+        mov     es,     bx
+        xor     bx,     bx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Preserve the extra segment and the bx register.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        push    es
+        push    bx
+    
+    .read_entry:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Preserve the ax, dx and bx registers
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        push    dx
+        push    ax
+        push    bx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Convert the cluster to LBA.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        call    _convert_cluster
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Move the value in the bx register to cx (sectors per cluster)
+        ;; and restore the bx register (offset to read into).
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     cx,     bx
+        pop     bx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; If the carry flag is set then we've reached the end of the file.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jc      .execute
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Decrement our sectors count.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        sub     di,     cx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Read the cluster into memory.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        call    _read_sectors
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; If di is zero the we've read all the sectors we need.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        and     di,     di
+        jz      .execute
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Restore the ax and dx registers.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        pop     ax
+        pop     dx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Get the next cluster.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        call    _next_cluster
+        jmp     short   .read_entry
+    
+    .execute:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Restore the ax, dx and bx registers.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        pop     ax
+        pop     dx
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; We'll pass the drive no. in cl.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        mov     cl,     [_drive_no]
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Jump to the new code.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        retf
+    
+    .error:
+    
+        call    _error
+        db      "NF",       HEX (0D),   HEX (0A),   HEX (00)
+
+;******************************************************************************
+; @function         _error
+;******************************************************************************
+_error:
+
+    pop     si
+    jmp     short   _error.next
+
+_error.print:
+
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_error.next:
+
+    lodsb
+    
+    and     al,     al
+    jnz     _error.print
+
+_error.done:
+
+    xor     ax,     ax
+    int     HEX (16)
+    int     HEX (19)
+
+%ifdef      __FAT12__
+;******************************************************************************
+; @function         _convert_cluster
+;******************************************************************************
+_convert_cluster:
+
+    cmp     ax,     HEX (0FF8)
+    jb      _convert_cluster.c3
+    
+    stc
+    ret
+
+_convert_cluster.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [bp - 20]
+    add     dx,     [bp - 18]
+    
+    ret
+
+;******************************************************************************
+; @function         _next_cluster
+;******************************************************************************
+_next_cluster:
+
+    push    cx
+    push    si
+    
+    mov     si,     ax
+
+_next_cluster.secoff:
+
+    mov     ax,     3
+    mul     si
+    shr     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_next_cluster.read_fat:
+
+    push    es
+    push    bx
+    
+    ;mov     bx,     (Mem.Stage2 >> 4) - HEX (40)
+    ;mov     es,     bx
+    ;xor     bx,     bx
+    
+    mov     ax,     [bp - 24]
+    mov     dx,     [bp - 22]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    mov     cx,     2
+    call    _read_sectors
+    
+    pop     bx
+    pop     es
+
+_next_cluster.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    push    ds
+    mov     ax,     es
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+    jnc     _next_cluster.even_cluster
+    
+    mov     cl,     4
+    shr     ax,     cl
+
+_next_cluster.even_cluster:
+
+    and     ax,     HEX (0FFF)
+
+_next_cluster.compare:
+
+    cmp     ax,     HEX (0FF8)
+    cmc
+
+_next_cluster.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+%endif
+
+%ifdef      __FAT16__
+;******************************************************************************
+; @function         _convert_cluster
+;******************************************************************************
+_convert_cluster:
+
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster.c3
+    
+    stc
+    ret
+
+_convert_cluster.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [bp - 20]
+    add     dx,     [bp - 18]
+    
+    ret
+
+;******************************************************************************
+; @function         _next_cluster
+;******************************************************************************
+_next_cluster:
+
+    push    cx
+    push    si
+
+_next_cluster.secoff:
+
+    shl     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_next_cluster.read_fat:
+
+    push    es
+    push    bx
+    
+    ;mov     bx,     (Mem.Stage2 >> 4) - HEX (40)
+    ;mov     es,     bx
+    ;xor     bx,     bx
+    
+    mov     ax,     [bp - 24]
+    mov     dx,     [bp - 22]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    mov     cx,     2
+    call    _read_sectors
+    
+    pop     bx
+    pop     es
+
+_next_cluster.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    mov     ax,     es
+    jnc     _next_cluster.first64
+    
+    add     ax,     HEX (1000)
+
+_next_cluster.first64:
+
+    push    ds
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+
+_next_cluster.compare:
+
+    cmp     ax,     HEX (FFF8)
+    cmc
+
+_next_cluster.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+%endif
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    di
+
+_read_sectors.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The di regsiter will be our retry counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (0005)
+
+_read_sectors.retry:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    push    dx
+    
+    div     word ptr [_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA % SPT         = sector - 1
+    
+    xchg    cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr [_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) % HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    
+    ror     ah
+    ror     ah                                                                  ; excess bits of cylinder no. must be 0 anyway
+    
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     [_drive_no]
+    stc
+    int     HEX (13)
+    jnc     _read_sectors.success                                                   ; CF = 0 if no error
+
+_read_sectors.failure:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     dl,     [_drive_no]
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the loop counter and retry if greater than zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     di
+    jnz     _read_sectors.retry
+    
+_read_sectors.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    mov     ax,     [_bytes_per_sector]
+    mov     cl,     4
+    shr     ax,     cl
+    
+    mov     cx,     es
+    add     cx,     ax
+    mov     es,     cx
+
+_read_sectors.no_incr:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop until cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _read_sectors.next
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Entry.Filename:                 db      "FREELDR SYS"
+Entry.Filename.Length:          equ     ($ - Entry.Filename)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pad until 510 bytes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+db      HEX (01FE) - (. - _start)   dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Boot signature.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+dw      HEX (AA55)
diff --git a/src/boot/freeldr/core/Makefile.unix b/src/boot/freeldr/core/Makefile.unix
new file mode 100644 (file)
index 0000000..3afab38
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: freeldr.sys
+
+clean:
+       for f in *.o; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in *.lst; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       if [ -f freeldr.sys ]; then rm -rf freeldr.sys; fi
+
+freeldr.sys: bootstrap.o config.o crlf.o disk.o error.o fat.o file.o freeldr.o int21.o ll.o mangle.o mem.o menu.o screen.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o xmalloc.o xrealloc.o ../libc/libc.a
+       ../../../utils/binutils/slink --oformat binary -o $@ $^
+
+%.o: %.asm
+       ../../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/boot/freeldr/core/Makefile.w32 b/src/boot/freeldr/core/Makefile.w32
new file mode 100644 (file)
index 0000000..7141a47
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: freeldr.sys
+
+clean:
+       for %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+       if exist freeldr.sys ( del /q freeldr.sys )
+
+freeldr.sys: bootstrap.o config.o crlf.o disk.o error.o fat.o file.o freeldr.o int21.o ll.o mangle.o mem.o menu.o screen.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o xmalloc.o xrealloc.o ../libc/libc.a
+       ../../../utils/binutils/slink --oformat binary -o $@ $^
+
+%.o: %.asm
+       ../../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/boot/freeldr/core/bootstrap.asm b/src/boot/freeldr/core/bootstrap.asm
new file mode 100644 (file)
index 0000000..d1c4d63
--- /dev/null
@@ -0,0 +1,1309 @@
+;******************************************************************************
+; @file             bootstrap.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Memory layout.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Mem.Stack.Top:                  equ     HEX (0840)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Define some offsets for the BPB.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _bytes_per_sector           (bp - 64)
+%define     _sectors_per_cluster        (bp - 62)
+%define     _reserved_sectors           (bp - 61)
+%define     _number_of_fats             (bp - 59)
+%define     _root_entries               (bp - 58)
+%define     _total_sectors16            (bp - 56)
+%define     _media_descriptor           (bp - 54)
+%define     _sectors_per_fat            (bp - 53)
+%define     _sectors_per_track          (bp - 51)
+%define     _heads_per_cylinder         (bp - 49)
+%define     _hidden_sectors             (bp - 47)
+%define     _total_sectors32            (bp - 43)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; FAT32 EBPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _sectors_per_fat32          (bp - 39)
+%define     _root_cluster               (bp - 35)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Other offsets used within this file.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _edd_available              (bp - 28)
+%define     _drive_no                   (bp - 26)
+
+%define     _fat_start                  (bp - 24)
+%define     _data_start                 (bp - 20)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; FAT32 offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _fat_secmask                (bp - 16)
+%define     _fat_secshift               (bp - 14)
+%define     _fat_sector                 (bp - 12)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Offsets of FAT12 and FAT16 convert cluster and next cluster functions.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _convert_cluster            (bp - 8)
+%define     _next_cluster               (bp - 6)
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and cx register as well as the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the convertional memory (in KBs) ...
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; ... And convert it into 16-byte paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     6
+    shl     ax,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reserve memory for a stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     (Mem.Stack.Top >> 4)
+    sub     ax,     cx
+    
+    mov     di,     ax
+    
+    popf
+    pop     cx
+    pop     ax
+    
+    mov     ss,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base and stack pointers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     Mem.Stack.Top
+    lea     sp,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no. passed to us.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, bx, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Transfer the drive no. into the dl register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure our edd_avaiable variable is zero by default.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [_edd_available],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Only check if we're booted from a hard disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    dl,     HEX (70)
+    jnz     _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (41)
+    mov     bx,     HEX (55AA)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then disk extensions a unavailable.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Bit 1 in the cx register should be set if disk extensions
+    ;; are present.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    shr     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Test for carry (from shr) too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sbb     bx,     HEX (AA55) - 1
+    jne     _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indicate that we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [_edd_available],      1
+
+_no_edd:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, bx, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    popf
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the extra segment and si register as they
+    ;; get clobbered by movsb.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    si
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB just above the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     ss
+    mov     es,     di
+    
+    mov     si,     11
+    lea     di,     [bp - 64]
+    
+    mov     cx,     25
+    rep     movsb
+    
+    cmp     byte ptr [HEX (01)],    HEX (58)
+    jne     _not_fat32
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we get here then we're dealing with FAT32, so first
+    ;; preserve the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the number of sectors per FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [HEX (24)]
+    stosw
+    
+    mov     ax,     [HEX (26)]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the root cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [HEX (2C)]
+    stosw
+    
+    mov     ax,     [HEX (2E)]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    di
+    push    ax
+    push    dx
+
+_calc_offsets:
+
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     [_hidden_sectors]
+    mov     di,     [_hidden_sectors + 2]
+    
+    add     si,     [_reserved_sectors]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_fat_start],       si
+    mov     [_fat_start + 2],       di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [_number_of_fats]
+    cbw
+    
+    push    ax
+    
+    mul     word ptr [_sectors_per_fat32 + 2]
+    add     di,     ax
+    
+    pop     ax
+    mul     word ptr [_sectors_per_fat32]
+    
+    add     ax,     si
+    adc     dx,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_data_start],      ax
+    mov     [_data_start + 2],      dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    pop     di
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [_bytes_per_sector]
+    shr     ax
+    shr     ax
+    dec     ax
+    
+    mov     [_fat_secmask],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+    
+    xchg    ax,     cx
+    inc     cx
+
+_secshift:
+
+    inc     ax
+    shr     cx
+    
+    cmp     cx,     1
+    jne     _secshift
+    
+    mov     [_fat_secshift],        ax
+    dec     cx
+    
+    mov     [_fat_sector],      cx
+    mov     [_fat_sector + 2],      cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_after_copy:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    popf
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers (need as _next_cluster pops both).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L6
+
+.L4:
+
+    push    dx
+    push    ax
+    push    bx
+    
+    call    _convert_cluster32
+    jc      .L7
+    
+    mov     cx,     bx
+    pop     bx
+
+.L5:
+
+    call    _read_sectors
+
+.L6:
+
+    pop     ax
+    pop     dx
+    
+    call    _nextcluster_fat32
+    jmp     short   .L4
+
+.L7:
+
+    pop     bx
+    pop     ax
+    pop     dx
+    
+    mov     cl,     4
+    shr     bx,     cl
+    
+    mov     cx,     es
+    add     cx,     bx
+    mov     es,     cx
+    
+    xor     dh,     dh
+    mov     dl,     [_drive_no]
+    
+    xor     bx,     bx
+    stc
+    
+    jmp     _all_read
+
+;******************************************************************************
+; @function         _not_fat32
+;******************************************************************************
+_not_fat32:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    ax
+    push    dx
+    
+    xor     ax,     ax
+    
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     [_hidden_sectors]
+    mov     di,     [_hidden_sectors + 2]
+    
+    add     si,     [_reserved_sectors]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset ready for the fathelper at the start of
+    ;; freeldr.sys.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_fat_start],       si
+    mov     [_fat_start + 2],       di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [_number_of_fats]
+    cbw
+    mul     word ptr [_sectors_per_fat]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the FAT offset to get the root directory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors the root directory requires.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0020)
+    mul     word ptr [_root_entries]
+    div     word ptr [_bytes_per_sector]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the root offset to get the data offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_data_start],      si
+    mov     [_data_start + 2],      di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    pop     di
+    
+    popf
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Previded we've got a clean stack, the carry flag should be set from
+    ;; the boot sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      .L3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the address of the next cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _getfattype
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers (need as _next_cluster pops both).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L1
+
+.L2:
+
+    push    dx
+    push    ax
+    push    bx
+    
+    call    [_convert_cluster]
+    jc      .L3
+    
+    mov     cx,     bx
+    pop     bx
+
+.L8:
+
+    push    bp
+    push    ax
+    push    bx
+    
+    mov     ax,     HEX (0E2E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     ax
+    pop     bp
+    call    _read_sectors
+
+.L1:
+
+    pop     ax
+    pop     dx
+    
+    call    [_next_cluster]
+    jmp     short   .L2
+
+.L3:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the screen.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    xor     cx,     cx
+    mov     dx,     HEX (184F)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the cursor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     ax
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the value in the bx register to a segment and add
+    ;; it to the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     4
+    shr     bx,     cl
+    
+    mov     cx,     es
+    add     cx,     bx
+    mov     es,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Pass the drive no. in dl.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dh,     dh
+    mov     dl,     [_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     bx,     bx
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to the main code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _all_read
+
+;******************************************************************************
+; @function         _convert_cluster12
+;******************************************************************************
+_convert_cluster12:
+
+    cmp     ax,     HEX (0FF8)
+    jb      _convert_cluster12.c3
+    
+    stc
+    ret
+
+_convert_cluster12.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [_data_start]
+    add     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster16
+;******************************************************************************
+_convert_cluster16:
+
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster16.c3
+    
+    stc
+    ret
+
+_convert_cluster16.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [_data_start]
+    add     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster32
+;******************************************************************************
+_convert_cluster32:
+
+    cmp     dx,     HEX (0FFF)
+    jne     _convert_cluster32.c3
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster32.c3
+    
+    stc
+    ret
+
+_convert_cluster32.c3:
+
+    mov     cx,     dx
+    
+    sub     ax,     2
+    sbb     cx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    xchg    cx,     ax
+    mul     bx
+    
+    xchg    ax,     cx
+    mul     bx
+    
+    add     dx,     cx
+    
+    add     ax,     [_data_start]
+    adc     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _getfattype
+;******************************************************************************
+_getfattype:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    xor     ax,     ax
+
+_getfattype.init:
+
+    mov     al,     [_sectors_per_cluster]
+    cbw
+    mov     si,     ax
+    
+    mov     di,     [_bytes_per_sector]
+    
+    xor     dx,     dx
+    xor     cx,     cx
+    
+    mov     ax,     [_total_sectors16]
+    and     ax,     ax
+    jnz     _getfattype.have_secs
+    
+    mov     ax,     [_total_sectors32]
+    mov     dx,     [_total_sectors32 + 2]
+
+_getfattype.have_secs:
+
+    sub     ax,     [_reserved_sectors]
+    sbb     dx,     0
+    
+    mov     cl,     [_number_of_fats]
+
+_getfattype.sec_fat_loop:
+
+    sub     ax,     [_sectors_per_fat]
+    sbb     dx,     0
+    loop    _getfattype.sec_fat_loop
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     [_root_entries]
+    mov     bx,     32
+    mul     bx
+    
+    add     ax,     di
+    adc     dx,     0
+    
+    sub     ax,     1
+    sbb     dx,     0
+    
+    div     di
+    mov     bx,     ax
+    
+    pop     dx
+    pop     ax
+    
+    sub     ax,     bx
+    sbb     dx,     0
+    
+    div     si
+    
+    cmp     ax,     4096
+    ja      _getfattype.fat16
+
+_getfattype.fat12:
+
+    mov     ax,     offset _convert_cluster12
+    mov     [_convert_cluster],     ax
+    
+    mov     ax,     offset _nextcluster_fat12
+    mov     [_next_cluster],        ax
+    
+    jmp     short   _getfattype.done
+
+_getfattype.fat16:
+
+    mov     ax,     offset _convert_cluster16
+    mov     [_convert_cluster],     ax
+    
+    mov     ax,     offset _nextcluster_fat16
+    mov     [_next_cluster],        ax
+
+_getfattype.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat12
+;******************************************************************************
+_nextcluster_fat12:
+
+    push    cx
+    push    si
+    
+    mov     si,     ax
+
+_nextcluster_fat12.secoff:
+
+    mov     ax,     3
+    mul     si
+    shr     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat12.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     [_fat_start]
+    mov     dx,     [_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat12.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat12.cn_exit
+
+_nextcluster_fat12.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat12.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat12.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    push    ds
+    mov     ax,     ss
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+    jnc     _nextcluster_fat12.even_cluster
+    
+    mov     cl,     4
+    shr     ax,     cl
+
+_nextcluster_fat12.even_cluster:
+
+    and     ax,     HEX (0FFF)
+
+_nextcluster_fat12.compare:
+
+    cmp     ax,     HEX (0FF8)
+    cmc
+
+_nextcluster_fat12.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat16
+;******************************************************************************
+_nextcluster_fat16:
+
+    push    cx
+    push    si
+
+_nextcluster_fat16.secoff:
+
+    shl     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat16.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     [_fat_start]
+    mov     dx,     [_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat16.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat16.cn_exit
+
+_nextcluster_fat16.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat16.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat16.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    mov     ax,     ss
+    jnc     _nextcluster_fat16.first64
+    
+    add     ax,     HEX (1000)
+
+_nextcluster_fat16.first64:
+
+    push    ds
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+
+_nextcluster_fat16.compare:
+
+    cmp     ax,     HEX (FFF8)
+    cmc
+
+_nextcluster_fat16.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat32
+;******************************************************************************
+_nextcluster_fat32:
+
+    push    es
+    push    bx
+    push    cx
+    push    di
+    
+    mov     di,     ax
+    and     di,     [_fat_secmask]
+    
+    mov     cx,     [_fat_secshift]
+
+_nextcluster_fat32.cn_loop:
+
+    shr     dx
+    rcr     ax
+    loop    _nextcluster_fat32.cn_loop
+    
+    shl     di
+    shl     di
+    
+    add     ax,     [_fat_start]
+    adc     dx,     [_fat_start + 2]
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat32.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat32.cn_exit
+
+_nextcluster_fat32.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     1
+    call    _read_sectors
+
+_nextcluster_fat32.cn_exit:
+
+    mov     ax,     es:[di]
+    mov     dx,     es:[di + 2]
+    
+    cmp     dx,     HEX (0FFF)
+    jne     _nextcluster_fat32.no_carry
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _nextcluster_fat32.no_carry
+    
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    stc
+    ret
+
+_nextcluster_fat32.no_carry:
+
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    clc
+    ret
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    di
+
+_read_sectors.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The di regsiter will be our retry counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (0005)
+
+_read_sectors.retry:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If disk extensions aren't avaiable then we need to use CHS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr [_edd_available],       1
+    jb      _read_sectors.chs
+
+_read_sectors.lba:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll create the LBA read on the stack.  8086 doesn't allow pushing
+    ;; values directly so we'll use si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    push    si
+    push    si
+    
+    push    dx
+    push    ax
+    push    es
+    push    bx
+    
+    mov     si,     1
+    push    si
+    
+    mov     si,     16
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The dl register needs to be set to the drive number before we alter
+    ;; the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     [_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need to set si to sp as the LBA read requires ds:si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment to the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ss
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (42)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cleanup the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was no carry the we successfully read the sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnc     _read_sectors.success
+
+_read_sectors.chs:
+
+    div     word ptr [_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA # SPT        = sector - 1
+    
+    mov     cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr [_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) # HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    ror     ah
+    ror     ah
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     [_drive_no]
+    stc
+    int     HEX (13)
+    jnc     _read_sectors.success
+
+_read_sectors.failure:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     dl,     [_drive_no]
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the loop counter and retry if greater than zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     di
+    jnz     _read_sectors.retry
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    add     bx,     [_bytes_per_sector]
+    jnc     _read_sectors.no_incr
+    
+    mov     cx,     es
+    add     ch,     HEX (10)
+    mov     es,     cx
+
+_read_sectors.no_incr:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop until cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _read_sectors.next
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     4
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (0E)
+    
+    push    bp
+    push    bx
+    
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     bp
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Make sure we fit inside 2048 bytes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+db      HEX (0800) - (. - _start)   dup (0)
diff --git a/src/boot/freeldr/core/config.asm b/src/boot/freeldr/core/config.asm
new file mode 100644 (file)
index 0000000..33916fe
--- /dev/null
@@ -0,0 +1,1015 @@
+;******************************************************************************
+; @file             config.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _get_command
+;******************************************************************************
+_get_command:
+
+    push    ax
+    push    cx
+    
+    xor     ax,     ax
+    xor     bx,     bx
+
+_get_command.loop:
+
+    call    _is_name_part
+    jc      _get_command.done
+    
+    mov     cl,     5
+    rol     bx,     cl
+    
+    lodsb
+    
+    or      al,     HEX (20)
+    xor     bx,     ax
+    
+    jmp     _get_command.loop
+
+_get_command.done:
+
+    pop     cx
+    pop     ax
+    
+    ret
+
+;******************************************************************************
+; @function         _is_name_beginner
+;******************************************************************************
+_is_name_beginner:
+
+    push    ax
+
+_is_name_beginner.check:
+
+    lodsb
+    
+    cmp     al,     '.'
+    je      .L2
+    
+    cmp     al,     '_'
+    je      .L2
+    
+    cmp     al,     'z'
+    ja      .L1
+    
+    cmp     al,     'a'
+    jae     .L2
+    
+    cmp     al,     'Z'
+    ja      .L1
+    
+    cmp     al,     'A'
+    jae     .L2
+
+.L1:
+
+    pop     ax
+    dec     si
+    
+    stc
+    ret
+
+.L2:
+
+    pop     ax
+    dec     si
+    
+    clc
+    ret
+
+;******************************************************************************
+; @function         _is_name_part
+;******************************************************************************
+_is_name_part:
+
+    push    ax
+
+_is_name_part.check:
+
+    lodsb
+    
+    cmp     al,     '.'
+    je      .L4
+    
+    cmp     al,     '_'
+    je      .L4
+    
+    cmp     al,     'z'
+    ja      .L3
+    
+    cmp     al,     'a'
+    jae     .L4
+    
+    cmp     al,     'Z'
+    ja      .L3
+    
+    cmp     al,     'A'
+    jae     .L4
+    
+    cmp     al,     '9'
+    ja      .L3
+    
+    cmp     al,     '0'
+    jae     .L4
+
+.L3:
+
+    pop     ax
+    dec     si
+    
+    stc
+    ret
+
+.L4:
+
+    pop     ax
+    dec     si
+    
+    clc
+    ret
+
+;******************************************************************************
+; @function         _is_digit
+;******************************************************************************
+_is_digit:
+
+    push    ax
+
+_is_digit.check:
+
+    lodsb
+    
+    cmp     al,     '0'
+    jb      .L6
+    
+    cmp     al,     '9'
+    ja      .L6
+
+.L5:
+
+    pop     ax
+    dec     si
+    
+    clc
+    ret
+
+.L6:
+
+    pop     ax
+    dec     si
+    
+    stc
+    ret
+
+;******************************************************************************
+; @function         _skip_whitespace
+;******************************************************************************
+_skip_whitespace:
+
+    push    ax
+
+_skip_whitespace.loop:
+
+    lodsb
+    
+    cmp     al,     ' '
+    je      _skip_whitespace.loop
+    
+    cmp     al,     '\t'
+    je      _skip_whitespace.loop
+
+_skip_whitespace.done:
+
+    dec     si
+    
+    pop     ax
+    ret
+
+
+;******************************************************************************
+; @function         _pc_default
+;******************************************************************************
+_pc_default:
+
+    push    ax
+    push    bx
+    push    cx
+    
+    xor     ax,     ax
+    xor     bx,     bx
+    mov     cx,     5
+    
+    call    _is_name_beginner
+    jc      _pc_default.done
+
+_pc_default.loop:
+
+    call    _is_name_part
+    jc      _pc_default.done
+    
+    lodsb
+    
+    rol     bx,     cl
+    xor     bx,     ax
+    
+    jmp     _pc_default.loop
+
+_pc_default.done:
+
+    mov     cs:[_pc_menu_default],      bx
+    
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _pc_kernel
+;******************************************************************************
+_pc_kernel:
+
+    push    ax
+    push    bx
+
+_pc_kernel.init:
+
+    mov     bx,     si
+
+_pc_kernel.next:
+
+    lodsb
+    
+    and     al,     al
+    je      _pc_kernel.unget
+    
+    cmp     al,     HEX (0A)
+    je      _pc_kernel.unget
+    
+    cmp     al,     ' '
+    je      _pc_kernel.unget
+    
+    jmp     short   _pc_kernel.next
+
+_pc_kernel.unget:
+
+    dec     si
+    
+    cmp     word ptr cs:[_curr_entry],      0
+    jne     _pc_kernel.alloc
+    
+    push    ax
+    push    bx
+    push    dx
+    push    ds
+    
+    mov     bx,     cs
+    mov     ds,     bx
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    mov     bx,     offset _error_kernel_without_label
+    call    _writestr
+    
+    pop     ds
+    pop     dx
+    pop     bx
+    pop     ax
+    jmp     _pc_kernel.done
+
+_pc_kernel.alloc:
+
+    mov     ax,     si
+    sub     ax,     bx
+    xor     dx,     dx
+    
+    add     ax,     1
+    adc     dx,     0
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    push    di
+    push    es
+    
+    mov     di,     cs:[_curr_entry]
+    mov     es,     di
+    xor     di,     di
+    
+    mov     es:[di + 4],    ax
+    pop     es
+    pop     di
+    
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     es,     ax
+    xor     di,     di
+    
+    mov     ah,     [si]
+    mov     byte ptr [si],      0
+    
+    mov     si,     bx
+
+_pc_kernel.copy:
+
+    lodsb
+    
+    or      al,     al
+    jz      _pc_kernel.all_copied
+    
+    stosb
+    jmp     short   _pc_kernel.copy
+
+_pc_kernel.all_copied:
+
+    xor     al,     al
+    stosb
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    
+    mov     [si],       ah
+
+_pc_kernel.done:
+
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _pc_label
+;******************************************************************************
+_pc_label:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    xor     ax,     ax
+    xor     bx,     bx
+    mov     cx,     5
+    
+    call    _is_name_beginner
+    jc      _pc_label.done
+
+_pc_label.loop:
+
+    call    _is_name_part
+    jc      _pc_label.check
+    
+    lodsb
+    
+    rol     bx,     cl
+    xor     bx,     ax
+    
+    jmp     _pc_label.loop
+
+_pc_label.check:
+
+    mov     cx,     cs:[_vec_seen_hashes + 4]
+    xor     di,     di
+
+_pc_label.check_loop:
+
+    and     cx,     cx
+    jz      _pc_label.alloc
+    
+    mov     ax,     cs:[_vec_seen_hashes + 0]
+    mov     es,     ax
+    xor     di,     di
+    
+    mov     ax,     es:[di]
+    add     di,     2
+    
+    cmp     ax,     bx
+    je      _pc_label.collision
+    
+    dec     cx
+    jmp     _pc_label.check_loop
+
+_pc_label.alloc:
+
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     ax,     bx
+    push    ax
+    
+    mov     ax,     offset _vec_seen_hashes
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    pop     ds
+    
+    mov     ax,     16
+    xor     dx,     dx
+    
+    push    ds
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    mov     cs:[_curr_entry],       ax
+    push    ax
+    
+    mov     es,     ax
+    xor     di,     di
+    
+    mov     ax,     bx
+    stosw
+    
+    mov     ax,     offset _menu_entries
+    push    ax
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    pop     ds
+    
+    cmp     cs:[_pc_menu_default],      bx
+    jne     _pc_label.done
+    
+    mov     ax,     cs:[_menu_entries + 4]
+    dec     ax
+    mov     cs:[_menu_default],     ax
+
+_pc_label.done:
+    
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+_pc_label.collision:
+
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    call    _error
+    db      "duplicate entry name found",       HEX (0D),   HEX (0A),   HEX (00)
+
+;******************************************************************************
+; @function         _pc_timeout
+;******************************************************************************
+_pc_timeout:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    xor     ax,     ax
+    xor     bx,     bx
+    xor     dx,     dx
+    
+    mov     cx,     10
+    xor     di,     di
+
+_pc_timeout.convert:
+
+    call    _is_digit
+    jc      _pc_timeout.done
+    
+    lodsb
+    push    ax
+    
+    mov     ax,     di
+    mul     cx
+    mov     di,     ax
+    
+    pop     ax
+    
+    test    dx,     dx
+    jnz     _pc_timeout.cap
+    
+    sub     al,     '0'
+    add     di,     ax
+    
+    cmp     di,     60
+    jb      _pc_timeout.convert
+
+_pc_timeout.check:
+
+    cmp     di,     60
+    jbe     _pc_timeout.done
+
+_pc_timeout.cap:
+
+    mov     di,     60
+
+_pc_timeout.done:
+
+    mov     cs:[_menu_timeout],     di
+    
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _pc_title
+;******************************************************************************
+_pc_title:
+
+    push    ax
+    push    bx
+
+_pc_title.init:
+
+    mov     bx,     si
+
+_pc_title.next:
+
+    lodsb
+    
+    and     al,     al
+    je      _pc_title.unget
+    
+    cmp     al,     HEX (0A)
+    je      _pc_title.unget
+    
+    jmp     short   _pc_title.next
+
+_pc_title.unget:
+
+    dec     si
+    
+    cmp     word ptr cs:[_curr_entry],      0
+    jne     _pc_title.alloc
+    
+    push    ax
+    push    bx
+    push    dx
+    push    ds
+    
+    mov     bx,     cs
+    mov     ds,     bx
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    mov     bx,     offset _error_title_without_label
+    call    _writestr
+    
+    pop     ds
+    pop     dx
+    pop     bx
+    pop     ax
+    jmp     _pc_title.done
+
+_pc_title.alloc:
+
+    mov     ax,     si
+    sub     ax,     bx
+    xor     dx,     dx
+
+    add     ax,     1
+    adc     dx,     0
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    push    di
+    push    es
+    
+    mov     di,     cs:[_curr_entry]
+    mov     es,     di
+    xor     di,     di
+    
+    mov     es:[di + 2],    ax
+    pop     es
+    pop     di
+    
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     es,     ax
+    xor     di,     di
+    
+    mov     ah,     [si]
+    mov     byte ptr [si],      0
+    
+    mov     si,     bx
+
+_pc_title.copy:
+
+    lodsb
+    
+    or      al,     al
+    jz      _pc_title.all_copied
+    
+    stosb
+    jmp     short   _pc_title.copy
+
+_pc_title.all_copied:
+
+    xor     al,     al
+    stosb
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    
+    mov     [si],       ah
+
+_pc_title.done:
+
+    pop     bx
+    pop     ax
+    ret
+
+
+;******************************************************************************
+; @function         _parse_config
+;******************************************************************************
+global      _parse_config
+_parse_config:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     4
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    mov     ax,     word ptr [bp + 4]
+    mov     cs:[_filename],     ax
+    
+    mov     word ptr [bp - 2],      0
+    
+    call    _load_line_create_internal_data
+    
+    and     ax,     ax
+    jz      _parse_config.done
+    
+    mov     word ptr [bp - 4],      ax
+
+_parse_config.read_line:
+
+    mov     ax,     word ptr [bp - 4]
+    push    ax
+    
+    mov     ax,     word ptr [bp + 6]
+    push    ax
+    
+    xor     ax,     ax
+    push    ax
+    push    ax
+    
+    mov     ax,     offset _line
+    push    ax
+    
+    call    _load_line
+    add     sp,     10
+    
+    and     ax,     ax
+    jnz     _parse_config.cleanup
+    
+    add     word ptr cs:[_line_number],     1
+
+_parse_config.got_line:
+
+    push    ds
+    
+    mov     ax,     [_line]
+    mov     ds,     ax
+    xor     si,     si
+    
+    call    _skip_whitespace
+    
+    call    _is_name_beginner
+    jc      _parse_config.check_eof
+    
+    call    _get_command
+
+_parse_config.find:
+
+    push    cx
+    push    si
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     si,     offset _pc_keywd_table
+    mov     cx,     offset _pc_keywd_count
+
+_parse_config.search:
+
+    lodsw
+    
+    cmp     bx,     ax
+    je      _parse_config.found
+    
+    lodsw
+    lodsw
+    loop    _parse_config.search
+    
+    inc     word ptr [bp - 2]
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    push    ax
+    push    dx
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    pop     dx
+    pop     ax
+    
+    mov     bx,     offset _error_badcfg
+    call    _writestr
+    
+    pop     ds
+    pop     si
+    pop     cx
+    jmp     _parse_config.next
+
+_parse_config.found:
+
+    lodsw
+    lodsw
+    
+    mov     bx,     ax
+    pop     ds
+    pop     si
+    pop     cx
+    
+    call    _skip_whitespace
+    mov     al,     [si]
+    
+    and     al,     al
+    jz      _parse_config.noparam
+    
+    cmp     al,     HEX (0A)
+    je      _parse_config.noparam
+    
+    call    bx
+    jmp     _parse_config.check_eof
+
+_parse_config.noparam:
+
+    pop     ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    inc     word ptr [bp - 2]
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    push    ax
+    push    dx
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    pop     dx
+    pop     ax
+    
+    mov     bx,     offset _error_noparam
+    call    _writestr
+    
+    jmp     _parse_config.read_line
+
+_parse_config.check_eof:
+
+    call    _skip_whitespace
+    lodsb
+    
+    and     al,     al
+    jz      _parse_config.next
+    
+    cmp     al,     HEX (0A)
+    je      _parse_config.next
+    
+    inc     word ptr [bp - 2]
+    pop     ds
+    
+    mov     bx,     cs:[_filename]
+    call    _writestr
+    
+    push    ax
+    push    dx
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     ax,     cs:[_line_number]
+    xor     dx,     dx
+    call    _writedec
+    
+    mov     al,     ':'
+    call    _writechr
+    
+    mov     al,     ' '
+    call    _writechr
+    
+    pop     dx
+    pop     ax
+    
+    mov     bx,     offset _error_junk
+    mov     [bx + 6],       al
+    
+    call    _writestr
+    jmp     _parse_config.read_line
+
+_parse_config.next:
+
+    pop     ds
+    jmp     _parse_config.read_line
+
+_parse_config.cleanup:
+
+    push    word ptr [bp - 4]
+    
+    call    _load_line_destroy_internal_data
+    add     sp,     2
+
+_parse_config.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     4
+    clc
+    
+    and     ax,     ax
+    jz      _parse_config.got_carry
+    
+    stc
+
+_parse_config.got_carry:
+
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_error_kernel_without_label:    db      "kernel specified outside label",                   HEX (0D),   HEX (0A),   HEX (00)
+_error_title_without_label:     db      "title specified outside label",                    HEX (0D),   HEX (0A),   HEX (00)
+
+_error_noparam:                 db      "missing parameter in lilo.cfg",                    HEX (0D),   HEX (0A),   HEX (00)
+_error_badcfg:                  db      "unknown keyword in lilo.cfg",                      HEX (0D),   HEX (0A),   HEX (00)
+_error_junk:                    db      "junk '",   HEX (00),   "' at the end of line",     HEX (0D),   HEX (0A),   HEX (00)
+
+_filename:                      dw      HEX (0000)
+_line_number:                   dw      HEX (0000)
+
+_curr_entry:                    dw      HEX (0000)
+_line:                          dw      HEX (0000)
+
+_pc_menu_default:               dw      HEX (0000)
+_vec_seen_hashes:               db      HEX (0006)      dup (0)
+
+%include    "../kwdhash.gen"
+_pc_keywd_size:                 equ     6
+
+align   4
+_pc_keywd_table:
+
+    dw      hash_default
+    dw      0
+    dw      _pc_default
+    
+    dw      hash_kernel
+    dw      0
+    dw      _pc_kernel
+    
+    dw      hash_label
+    dw      0
+    dw      _pc_label
+    
+    dw      hash_timeout
+    dw      0
+    dw      _pc_timeout
+    
+    dw      hash_title
+    dw      0
+    dw      _pc_title
+
+_pc_keywd_count:                equ     ($ - _pc_keywd_table) / _pc_keywd_size
diff --git a/src/boot/freeldr/core/crlf.asm b/src/boot/freeldr/core/crlf.asm
new file mode 100644 (file)
index 0000000..b715115
--- /dev/null
@@ -0,0 +1,33 @@
+;******************************************************************************
+; @file             crlf.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _crlf
+;******************************************************************************
+global      _crlf
+_crlf:
+
+    push    ax
+    push    bx
+    push    dx
+    push    bp
+    
+    mov     ah,     HEX (0E)
+    mov     al,     HEX (0D)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    mov     ah,     HEX (0E)
+    mov     al,     HEX (0A)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bp
+    pop     dx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/boot/freeldr/core/disk.asm b/src/boot/freeldr/core/disk.asm
new file mode 100644 (file)
index 0000000..21e8920
--- /dev/null
@@ -0,0 +1,238 @@
+;******************************************************************************
+; @file             disk.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+global      _read_sectors
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    si
+    push    di
+    push    es
+
+_read_sectors.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The di regsiter will be our retry counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (0005)
+
+_read_sectors.retry:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If disk extensions aren't avaiable then we need to use CHS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_edd_available],       1
+    jb      _read_sectors.chs
+
+_read_sectors.lba:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll create the LBA read on the stack.  8086 doesn't allow pushing
+    ;; values directly so we'll use si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    push    si
+    push    si
+    
+    push    dx
+    push    ax
+    push    es
+    push    bx
+    
+    mov     si,     1
+    push    si
+    
+    mov     si,     16
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The dl register needs to be set to the drive number before we alter
+    ;; the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     cs:[_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need to set si to sp as the LBA read requires ds:si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment to the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ss
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (42)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cleanup the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was no carry the we successfully read the sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnc     _read_sectors.success
+
+_read_sectors.chs:
+
+    div     word ptr cs:[_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA # SPT        = sector - 1
+    
+    mov     cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr cs:[_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) # HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    ror     ah
+    ror     ah
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     cs:[_drive_no]
+    stc
+    int     HEX (13)
+    jnc     _read_sectors.success
+
+_read_sectors.failure:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     dl,     cs:[_drive_no]
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the loop counter and retry if greater than zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     di
+    jnz     _read_sectors.retry
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the bytes per sector to bx to get the next offset to read in to.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     bx,     cs:[_bytes_per_sector]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop until cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _read_sectors.next
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _drive_no
+_drive_no:                      db      HEX (00)
+
+global      _edd_available
+_edd_available:                 dw      HEX (0000)
+
+global      _disk_scratch
+_disk_scratch:                  dw      HEX (0000)
diff --git a/src/boot/freeldr/core/error.asm b/src/boot/freeldr/core/error.asm
new file mode 100644 (file)
index 0000000..40f6dbd
--- /dev/null
@@ -0,0 +1,85 @@
+;******************************************************************************
+; @file             _error.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _error
+;******************************************************************************
+global      _error
+_error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the address of the string from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump passed printing so that we get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _error.next
+
+_error.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character using int 21/ah=02.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_error.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _error.print
+
+_error.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Wait for a keypress.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    int     HEX (16)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Stop floppy motor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     HEX (03F2)
+    xor     al,     al
+    out     dx,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cold reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     bx,     HEX (0472)
+    mov     word ptr es:[bx],   0
+    
+    jmp     HEX (F000) : HEX (FFF0)
diff --git a/src/boot/freeldr/core/fat.asm b/src/boot/freeldr/core/fat.asm
new file mode 100644 (file)
index 0000000..73ed6c9
--- /dev/null
@@ -0,0 +1,462 @@
+;******************************************************************************
+; @file             fat.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _convert_cluster12
+;******************************************************************************
+global      _convert_cluster12
+_convert_cluster12:
+
+    cmp     ax,     HEX (0FF8)
+    jb      _convert_cluster12.c3
+    
+    stc
+    ret
+
+_convert_cluster12.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster16
+;******************************************************************************
+global      _convert_cluster16
+_convert_cluster16:
+
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster16.c3
+    
+    stc
+    ret
+
+_convert_cluster16.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster32
+;******************************************************************************
+global      _convert_cluster32
+_convert_cluster32:
+
+    cmp     dx,     HEX (0FFF)
+    jne     _convert_cluster32.c3
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster32.c3
+    
+    stc
+    ret
+
+_convert_cluster32.c3:
+
+    mov     cx,     dx
+    
+    sub     ax,     2
+    sbb     cx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    xchg    cx,     ax
+    mul     bx
+    
+    xchg    ax,     cx
+    mul     bx
+    
+    add     dx,     cx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat12
+;******************************************************************************
+global      _nextcluster_fat12
+_nextcluster_fat12:
+
+    push    cx
+    push    si
+    
+    mov     si,     ax
+
+_nextcluster_fat12.secoff:
+
+    mov     ax,     3
+    mul     si
+    shr     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat12.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     cs:[_fat_start]
+    mov     dx,     cs:[_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat12.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat12.cn_exit
+
+_nextcluster_fat12.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat12.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat12.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    push    ds
+    mov     ax,     cs:[_fat_seg]
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+    jnc     _nextcluster_fat12.even_cluster
+    
+    mov     cl,     4
+    shr     ax,     cl
+
+_nextcluster_fat12.even_cluster:
+
+    and     ax,     HEX (0FFF)
+
+_nextcluster_fat12.compare:
+
+    cmp     ax,     HEX (0FF8)
+    cmc
+
+_nextcluster_fat12.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat16
+;******************************************************************************
+global      _nextcluster_fat16
+_nextcluster_fat16:
+
+    push    cx
+    push    si
+
+_nextcluster_fat16.secoff:
+
+    shl     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat16.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     cs:[_fat_start]
+    mov     dx,     cs:[_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat16.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat16.cn_exit
+
+_nextcluster_fat16.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat16.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat16.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    mov     ax,     cs:[_fat_seg]
+    jnc     _nextcluster_fat16.first64
+    
+    add     ax,     HEX (1000)
+
+_nextcluster_fat16.first64:
+
+    push    ds
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+
+_nextcluster_fat16.compare:
+
+    cmp     ax,     HEX (FFF8)
+    cmc
+
+_nextcluster_fat16.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat32
+;******************************************************************************
+global      _nextcluster_fat32
+_nextcluster_fat32:
+
+    push    es
+    push    bx
+    push    cx
+    push    di
+    
+    mov     di,     ax
+    and     di,     cs:[_fat_secmask]
+    
+    mov     cx,     cs:[_fat_secshift]
+
+_nextcluster_fat32.cn_loop:
+
+    shr     dx
+    rcr     ax
+    loop    _nextcluster_fat32.cn_loop
+    
+    shl     di
+    shl     di
+    
+    add     ax,     cs:[_fat_start]
+    adc     dx,     cs:[_fat_start + 2]
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat32.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat32.cn_exit
+
+_nextcluster_fat32.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     1
+    call    _read_sectors
+
+_nextcluster_fat32.cn_exit:
+
+    mov     ax,     es:[di]
+    mov     dx,     es:[di + 2]
+    
+    cmp     dx,     HEX (0FFF)
+    jne     _nextcluster_fat32.no_carry
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _nextcluster_fat32.no_carry
+    
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    stc
+    ret
+
+_nextcluster_fat32.no_carry:
+
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    clc
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _fat_bpb
+_fat_bpb:
+
+    db      25      dup (0)
+
+global      _fat_jump
+_fat_jump:
+
+    db      HEX (EB)
+    db      HEX (00)
+    db      HEX (90)
+
+global      _fat_seg
+_fat_seg:
+
+    dw      HEX (0000)
+
+global      _next_cluster
+_next_cluster:
+
+    dw      HEX (0000)
+
+global      _convert_cluster
+_convert_cluster:
+
+    dw      HEX (0000)
+
+global      _fat_secmask
+_fat_secmask:
+
+    dw      HEX (0000)
+
+global      _fat_secshift
+_fat_secshift:
+
+    dw      HEX (0000)
+
+global      _fat_sector
+_fat_sector:
+
+    dw      HEX (0000)
+
+global      _secsperclust
+_secsperclust:
+
+    dw      HEX (0000)
+
+global      _clustsize
+_clustsize:
+
+    dw      HEX (0000)
+
+global      _sectors_per_fat32
+_sectors_per_fat32:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _root_cluster
+_root_cluster:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _fat_start
+_fat_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _root_start
+_root_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _data_start
+_data_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
diff --git a/src/boot/freeldr/core/fat.inc b/src/boot/freeldr/core/fat.inc
new file mode 100644 (file)
index 0000000..e4cd3fb
--- /dev/null
@@ -0,0 +1,20 @@
+%ifndef     _FAT_INC
+%define     _FAT_INC
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Offsets into the BPB.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _bytes_per_sector           (_fat_bpb + 0)
+%define     _sectors_per_cluster        (_fat_bpb + 2)
+%define     _reserved_sectors           (_fat_bpb + 3)
+%define     _number_of_fats             (_fat_bpb + 5)
+%define     _root_entries               (_fat_bpb + 6)
+%define     _total_sectors16            (_fat_bpb + 8)
+%define     _media_descriptor           (_fat_bpb + 10)
+%define     _sectors_per_fat            (_fat_bpb + 11)
+%define     _sectors_per_track          (_fat_bpb + 13)
+%define     _heads_per_cylinder         (_fat_bpb + 15)
+%define     _hidden_sectors             (_fat_bpb + 17)
+%define     _total_sectors32            (_fat_bpb + 21)
+
+%endif      ; _FAT_INC
diff --git a/src/boot/freeldr/core/file.asm b/src/boot/freeldr/core/file.asm
new file mode 100644 (file)
index 0000000..fa437ba
--- /dev/null
@@ -0,0 +1,1207 @@
+;******************************************************************************
+; @file             file.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _read_cluster
+;******************************************************************************
+_read_cluster:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer to the stack pointer and reserve
+    ;; some space.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     36
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    push    ds
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need to preserve the data segment and the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the extra segment and the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment and initialize the
+    ;; si register with the offset of our BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    mov     si,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the stack segment and load the
+    ;; address that we're saving at.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss
+    mov     es,     ax
+    lea     di,     [bp - 36]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Also save the drive number and the edd flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     cs:[_drive_no]
+    stosb
+    
+    mov     ax,     cs:[_edd_available]
+    stosw
+    
+    mov     ax,     cs:[_fat_start]
+    stosw
+    
+    mov     ax,     cs:[_fat_start + 2]
+    stosw
+    
+    mov     ax,     cs:[_data_start]
+    stosw
+    
+    mov     ax,     cs:[_data_start + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the si register and the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the extra segment and the si register again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the data segment to the extra segment and add 4 to si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es
+    mov     ds,     ax
+    add     si,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the extra segment to the code segment and set the di register
+    ;; to the offset of our BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     es,     ax
+    mov     di,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the si register and the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the drive number and edd available flag from the info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     es:[si + 29]
+    mov     cs:[_drive_no],         al
+    
+    mov     ax,     es:[si + 44]
+    mov     cs:[_fat_start],        ax
+    
+    mov     ax,     es:[si + 46]
+    mov     cs:[_fat_start + 2],    ax
+    
+    mov     ax,     es:[si + 48]
+    mov     cs:[_data_start],       ax
+    
+    mov     ax,     es:[si + 50]
+    mov     cs:[_data_start + 2],   ax
+    
+    mov     ax,     es:[si + 52]
+    mov     cs:[_edd_available],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_read_cluster.find:
+
+    push    si
+    
+    mov     bx,     es:[si + 54]
+
+_read_cluster.walk:
+
+    and     ax,     ax
+    jz      _read_cluster.read
+    
+    call    bx
+    jnc     _read_cluster.found
+    
+    pop     si
+    pop     cx
+    pop     bx
+    
+    jmp     _read_cluster.done
+
+_read_cluster.found:
+
+    dec     ax
+    jnz     _read_cluster.walk
+
+_read_cluster.read:
+
+    pop     si
+    pop     dx
+    pop     ax
+    
+    mov     bx,     es:[si + 56]
+    
+    call    bx
+    jc      _read_cluster.done
+    
+    mov     cx,     bx
+    
+    mov     bx,     es:[si + 58]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    call    _read_sectors
+
+_read_cluster.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the stack segment and load the
+    ;; address that we stored the BPB too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss
+    mov     ds,     ax
+    lea     si,     [bp - 36]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the code segment and initialize the
+    ;; si register with the offset of our BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     es,     ax
+    mov     di,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the drive number and edd available flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    mov     cs:[_drive_no],         al
+    
+    lodsw
+    mov     cs:[_edd_available],    ax
+    
+    lodsw
+    mov     cs:[_fat_start],        ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_data_start],       ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],   ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     36
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _getc
+;******************************************************************************
+_getc:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    mov     word ptr [bp - 2],      0
+
+_getc.is_eof:
+
+    mov     ax,     es:[si + 38]
+    mov     dx,     es:[si + 40]
+    
+    mov     cx,     ax
+    or      cx,     dx
+    jz      _getc.done
+
+_getc.check:
+
+    cmp     dx,     es:[si + 36]
+    ja      _getc.check2
+    
+    cmp     dx,     es:[si + 36]
+    jne     _getc.done
+    
+    cmp     ax,     es:[si + 34]
+    jbe     _getc.done
+
+_getc.check2:
+
+    mov     ax,     es:[si + 34]
+    mov     dx,     es:[si + 36]
+    
+    mov     cx,     es:[si + 42]
+    div     cx
+    
+    and     dx,     dx
+    jnz     _getc.loaded
+    
+    mov     bx,     es:[si + 30]
+    mov     cx,     es:[si + 32]
+    call    _read_cluster
+
+_getc.loaded:
+
+    push    es
+    
+    mov     bx,     es:[si + 58]
+    mov     es,     bx
+    mov     bx,     dx
+    mov     al,     es:[bx]
+    
+    mov     bx,     ds
+    mov     es,     bx
+    stosb
+    
+    mov     bx,     es
+    mov     ds,     bx
+    
+    pop     es
+    inc     word ptr [bp - 2]
+    
+    add     word ptr es:[si + 34],      1
+    adc     word ptr es:[si + 36],      0
+
+_getc.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    clc
+    
+    pop     bp
+    ret
+
+_getc.error:
+
+    xor     ax,     ax
+    
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    stc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _get_file_handle
+;******************************************************************************
+_get_file_handle:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    es
+    
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs:[_vec_files + 0]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check to see if our vector is empty.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs:[_vec_files + 2]
+    
+    and     cx,     cx
+    jz      _get_file_handle.done
+
+_get_file_handle.search:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then we have a free entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _get_file_handle.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     bx,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Increase our counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     word ptr [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _get_file_handle.search
+
+_get_file_handle.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set ax to the index of the file plus 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp - 2]
+    add     ax,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag to indicate success.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and eturn to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+
+;******************************************************************************
+; @function         _close_file
+;******************************************************************************
+global      _close_file
+_close_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    si
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then we have a free entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    jne     _close_file.ok
+
+_close_file.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     si
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     6
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_close_file.ok:
+
+    push    es
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Our file handle info contains a pointer to a buffer so free it.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[di + 58]
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free our entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    
+    call    _free
+    add     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the entry to zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es:[bx],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract 1 from the length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     word ptr cs:[_vec_files + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     si
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Not sure what ax should be so just clear it for now and clear the
+    ;; carray flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function         _open_file
+;******************************************************************************
+global      _open_file
+_open_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the di register with the file name.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out bh and set bl to the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     bh,     bh
+    mov     bl,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Walk the path until we hit the last '\'.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _walk_path
+    jnc     _open_file.found_dir
+
+_open_file.not_found:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     3
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.found_dir:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Mangle the file name and search for it in the file system.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _mangle_dos_name
+    jc      _open_file.name_error
+    
+    call    _search_dos_dir
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then we couldn't find the specified file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _open_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax register should contain information about the file so
+    ;; copy it into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment as the code segment and copy the value
+    ;; in the ax register into the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The info passed back to us from _search_dos_dir should contain the
+    ;; entry type at offset 8 so move that into the cl register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     es:[bx + 8]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Was the entry a file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    cl,     HEX (18)
+    jz      _open_file.got_file
+
+_open_file.name_error:
+
+    pop     bx
+    pop     di
+
+_open_file.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.got_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get an available file info entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _get_file_handle
+    jnc     _open_file.got_handle
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     4
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.got_handle:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax register
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate memory for the file info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     64
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    mov     es,     ax
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value 1 as the first word to indicate that we need
+    ;; to be read
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value in the code segment into the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     cs
+    mov     ds,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the si register with the address of our BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB to the file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the drive number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     cs:[_drive_no]
+    stosb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the starting cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 0]
+    stosw
+    
+    mov     ax,     cs:[si + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; File pointer starts at zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the file size.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 4]
+    stosw
+    
+    mov     ax,     cs:[si + 6]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the size of a cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_clustsize]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the FAT start.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_fat_start]
+    stosw
+    
+    mov     ax,     cs:[_fat_start + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the data start.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_data_start]
+    stosw
+    
+    mov     ax,     cs:[_data_start + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store wheither edd features are available.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_edd_available]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the address of our next cluster function.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_next_cluster]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the address of our convert cluster function.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_convert_cluster]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate memory for a buffer that will be used to keep track of
+    ;; the current data read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_clustsize]
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore ax and re-push it to the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    push    ax
+
+_open_file.check:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached the capacity of our "vector array"?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     ax,     cs:[_vec_files + 2]
+    jb      _open_file.no_push
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so add the file info to our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    
+    mov     bx,     offset _vec_files
+    push    bx
+    
+    call    _vec_push
+    add     sp,     4
+    
+    jmp     short   _open_file.done
+
+_open_file.no_push:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value that in the extra segment into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the address of our vector array.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs:[_vec_files + 0]
+    mov     es,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the dx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiply by two to get the offset into the vector array.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the offset into bx and set it to the value that we copied into
+    ;; the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    mov     es:[bx],    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add one to our vector length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     word ptr cs:[_vec_files + 4]
+
+_open_file.done:
+
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Ckear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function         _read_file
+;******************************************************************************
+global      _read_file
+_read_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the base pointer to the stack pointer and make some room to store
+    ;; some values within this function.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    es
+    push    ds
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure our total bytes read is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    cx
+    
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    pop     cx
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then the file handle is invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _read_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-initialize the extra segment but this time with the address
+    ;; of the vector entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    xor     si,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we're not write-only.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[si + 2],   1
+    je      _read_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the buffer offset (dx) into the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     dx
+
+_read_file.loop:
+
+    call    _getc
+    jc      _read_file.error
+    
+    and     ax,     ax
+    jz      _read_file.done
+    
+    inc     word ptr [bp - 2]
+    loop    _read_file.loop
+
+_read_file.done:
+
+    mov     ax,     [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_read_file.error:
+
+    mov     ax,     6
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_vec_files:                     db     6        dup (0)
diff --git a/src/boot/freeldr/core/freeldr.asm b/src/boot/freeldr/core/freeldr.asm
new file mode 100644 (file)
index 0000000..38ca233
--- /dev/null
@@ -0,0 +1,1382 @@
+;******************************************************************************
+; @file             freeldr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Memory layout.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Mem.Kernel:                     equ     HEX (0600)
+
+;******************************************************************************
+; @function         _all_read
+;******************************************************************************
+global      _all_read
+_all_read:
+
+    jnc     _not_fat32
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the value that's in the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the offset of our _fat_bpb in the di register (where we want to
+    ;; copy the BPB to).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load the address of the base pointer minus 64 (start of the BPB).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lea     si,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB to our _fat_bpb offset
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy some other variables.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (58)
+    mov     [_fat_jump + 1],            al
+    
+    mov     ax,     word ptr [bp - 39]
+    mov     [_sectors_per_fat32],       ax
+    
+    mov     ax,     word ptr [bp - 37]
+    mov     [_sectors_per_fat32 + 2],   ax
+    
+    mov     ax,     word ptr [bp - 35]
+    mov     [_root_cluster],        ax
+    
+    mov     ax,     word ptr [bp - 33]
+    mov     [_root_cluster + 2],    ax
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     [_edd_available],       ax
+    
+    mov     ax,     word ptr [bp - 24]
+    mov     [_fat_start],           ax
+    
+    mov     ax,     word ptr [bp - 22]
+    mov     [_fat_start + 2],       ax
+    
+    mov     ax,     word ptr [bp - 20]
+    mov     [_data_start],          ax
+    
+    mov     ax,     word ptr [bp - 18]
+    mov     [_data_start + 2],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    dl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the stack segment with the value stored in bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ss,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We should only need a little room for the stack so set the
+    ;; stack pointer to 512.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     sp,     HEX (0200)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_bytes_per_sector]
+    shr     ax
+    shr     ax
+    dec     ax
+    
+    mov     cs:[_fat_secmask],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+    xchg    ax,     cx
+
+.L5:
+
+    inc     ax
+    shr     cx
+    
+    cmp     cx,     1
+    jne     .L5
+    
+    mov     cs:[_fat_secshift],     ax
+    dec     cx
+    
+;    mov     cs:[_fat_sector],       cx
+;    mov     cs:[_fat_sector + 2],   cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set our next cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set our convert cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to our main code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _real_start
+
+_not_fat32:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the value that's in the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the offset of our _fat_bpb in the di register (where we want to
+    ;; copy the BPB to).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load the address of the base pointer minus 64 (start of the BPB).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lea     si,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB to our _fat_bpb offset
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    dl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy some other variables.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (3C)
+    mov     [_fat_jump + 1],        al
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     [_edd_available],       ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the stack segment with the value stored in bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ss,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We should only need a little room for the stack so set the
+    ;; stack pointer to 512.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     sp,     HEX (0200)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the next cluster FAT type.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    mov     al,     [_sectors_per_cluster]
+    cbw
+    mov     si,     ax
+    
+    mov     di,     [_bytes_per_sector]
+    
+    xor     dx,     dx
+    xor     cx,     cx
+    
+    mov     ax,     [_total_sectors16]
+    and     ax,     ax
+    jnz     .L1
+    
+    mov     ax,     [_total_sectors32]
+    mov     dx,     [_total_sectors32 + 2]
+
+.L1:
+
+    sub     ax,     [_reserved_sectors]
+    sbb     dx,     0
+    
+    mov     cl,     [_number_of_fats]
+
+.L2:
+
+    sub     ax,     [_sectors_per_fat]
+    sbb     dx,     0
+    loop    .L2
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     [_root_entries]
+    mov     bx,     32
+    mul     bx
+    
+    add     ax,     di
+    adc     dx,     0
+    
+    sub     ax,     1
+    sbb     dx,     0
+    
+    div     di
+    mov     bx,     ax
+    
+    pop     dx
+    pop     ax
+    
+    sub     ax,     bx
+    sbb     dx,     0
+    
+    div     si
+    
+    cmp     ax,     4096
+    ja      .L3
+    
+    mov     ax,     offset _nextcluster_fat12
+    mov     cs:[_next_cluster],     ax
+    
+    mov     ax,     offset _convert_cluster12
+    mov     cs:[_convert_cluster],      ax
+    
+    jmp     short   .L4
+
+.L3:
+
+    mov     ax,     offset _nextcluster_fat16
+    mov     cs:[_next_cluster],     ax
+    
+    mov     ax,     offset _convert_cluster16
+    mov     cs:[_convert_cluster],      ax
+
+.L4:
+
+    xor     ax,     ax
+    xor     dx,     dx
+    
+    mov     si,     [_hidden_sectors]
+    mov     di,     [_hidden_sectors + 2]
+    
+    add     si,     [_reserved_sectors]
+    adc     di,     0
+    
+    mov     [_fat_start],       si
+    mov     [_fat_start + 2],       di
+    
+    mov     al,     [_number_of_fats]
+    cbw
+    mul     word ptr [_sectors_per_fat]
+    
+    add     si,     ax
+    adc     di,     dx
+    
+    mov     [_root_start],      si
+    mov     [_root_start + 2],      di
+    
+    mov     ax,     32
+    mul     word ptr [_root_entries]
+    div     word ptr [_bytes_per_sector]
+    
+    add     si,     ax
+    adc     si,     dx
+    
+    mov     [_data_start],      si
+    mov     [_data_start + 2],      di
+    
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+
+    jmp     _real_start
+
+;******************************************************************************
+; @function         _restore_and_jump
+;******************************************************************************
+_restore_and_jump:
+
+    cld
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     si,     offset _interrupts_list
+    mov     bx,     offset _interrupts_list_end
+    
+    cli
+
+_restore_and_jump.next:
+
+    cmp     si,     bx
+    je      _restore_and_jump.done
+    
+    lodsb
+    
+    mov     di,     ax
+    shl     di
+    shl     di
+    
+    movsw
+    movsw
+    
+    jmp     short   _restore_and_jump.next
+
+_restore_and_jump.done:
+
+    pop     di
+    pop     es
+    pop     ds
+    pop     cx
+    pop     bx
+    pop     ax
+    pop     si
+    pop     dx
+    
+    push    es
+    push    di
+    retf
+
+;******************************************************************************
+; @function         _bootstrap
+;******************************************************************************
+_bootstrap:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment to the segment we'll load the
+    ;; kernel too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     Mem.Kernel >> 4
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the di register and push the segment:offset to the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    push    es
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the cluster again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the data from DS:SI to ES:DI.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Transfer registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     dx
+    pop     ax
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Far jump to execute the kernel.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    retf
+
+_bootstrap_len:                 equ     ($ - offset _bootstrap)
+
+;******************************************************************************
+; @function         _clear_kbd
+;******************************************************************************
+_clear_kbd:
+
+    push    ax
+
+_clear_kbd.loop:
+
+    mov     ah,     HEX (01)
+    int     HEX (16)
+    jz      _clear_kbd.done
+    
+    xor     ah,     ah
+    int     HEX (16)
+    
+    jmp     short   _clear_kbd.loop
+
+_clear_kbd.done:
+
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _int19_handler
+;******************************************************************************
+_int19_handler:
+
+    cld
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     si,     offset _interrupts_list
+    mov     bx,     offset _interrupts_list_end
+    
+    cli
+
+_int19_handler.next:
+
+    cmp     si,     bx
+    je      _int19_handler.done
+    
+    lodsb
+    
+    mov     di,     ax
+    shl     di
+    shl     di
+    
+    movsw
+    movsw
+    
+    jmp     short   _int19_handler.next
+
+_int19_handler.done:
+
+    int     HEX (19)
+
+;******************************************************************************
+; @function         _real_start
+;******************************************************************************
+_real_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure that the keyboard buffer is cleared.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _clear_kbd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the sectors per cluster to a word.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [_sectors_per_cluster]
+    cbw
+    mov     [_secsperclust],        ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; How big is a cluster, really?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mul     word ptr [_bytes_per_sector]
+    mov     [_clustsize],           ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the screen size.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _adjust_screen
+
+_setup_malloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First we'll move the value in the stack pointer into the ax register
+    ;; and clear the dx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     sp
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Do we have any left over bytes (size % 16).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so we got the right segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jz      _segment_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Yep, we have linguring bytes so increase the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the zero flag is set then we have overflowed
+    ;; (greater than 65535 bytes)
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _segment_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Just for good measure set the data segment to the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print an error.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "segment overflow",     HEX (0D),   HEX (0A),   HEX (00)
+
+_segment_ok:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Now that we have the amount of segments that the stack pointer takes
+    ;; up we need to add the stack segment to get the first available segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ss
+    add     ax,     bx
+    
+    mov     [_free_seg],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the total memory (in KBs) and convert it to paragrahps for the
+    ;; maximum segment value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    mov     cl,     6
+    shl     ax,     cl
+    
+    mov     [_max_seg],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the di register with our free segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     [_free_seg]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register ready for stosw.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+
+_clear_memory:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we've reached out max segment then we've cleared all our
+    ;; free memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     di,     [_max_seg]
+    je      _setup_interrupts
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve some registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    cx
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the value in the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll be clearing 128 words (i.e 128 * 2) at a time.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     128
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value in the ax register into es:di unitl cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    rep     stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore our registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add 16 to get the next segment.
+    ;;
+    ;;     E.g. (0050:00ff -> 0x05ff) + 1 = 0060:0000 -> 0x0600.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     di,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop back to the clear the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _clear_memory
+
+_setup_interrupts:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts while we set everything up.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Setup si and bx to point to our list and list end.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _interrupts_list
+    mov     bx,     offset _interrupts_list_end
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+
+.L6:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we're not at the end of our interrupts list.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     si,     bx
+    je      .L7
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a byte from DS:SI to the al register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value into the DI register and multiple by 4 to get the
+    ;; correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     ax
+    shl     di
+    shl     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the address at the memory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     es:[di]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value of DS:SI to ES:DI.
+    ;;
+    ;;     Note: This will increment both the SI and DI registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    movsw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the address we previously got.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [si - 2],   dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the segment at the memory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     es:[di]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The segment of the new interrupt will be our code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es:[di],    cs
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the segment we previously got.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [si],       dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to the SI register to account for the saved segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop back for the next entry (if there is one).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L6
+
+.L7:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     bx
+    pop     ax
+
+_reserve_fat:
+    
+    mov     ax,     [_bytes_per_sector]
+    shl     ax
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    mov     [_fat_seg],     ax
+
+_reserve_scratch:
+
+    mov     ax,     [_bytes_per_sector]
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    mov     [_disk_scratch],    ax
+
+_main:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load configuration File.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     offset _freeldr_cfg1
+    push    di
+    
+    call    _fopen
+    add     sp,     2
+    
+    and     ax,     ax
+    jnz     _config_open
+    
+    mov     di,     offset _freeldr_cfg2
+    push    di
+    
+    call    _fopen
+    add     sp,     2
+    
+    and     ax,     ax
+    jnz     _config_open
+    
+    mov     di,     offset _freeldr_cfg3
+    push    di
+    
+    call    _fopen
+    add     sp,     2
+    
+    and     ax,     ax
+    jnz     _config_open
+    
+    call    _error
+    db      "error: failed to find configuration file",     HEX (0D),   HEX (0A),   HEX (00)
+
+_config_open:
+
+    push    ax
+    push    di
+    
+    call    _parse_config
+    jnc     _config_ok
+    
+    add     sp,     2
+    
+    call    _fclose
+    add     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Wait for a keypress.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    int     HEX (16)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Stop floppy motor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     HEX (03F2)
+    xor     al,     al
+    out     dx,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cold reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     bx,     HEX (0472)
+    mov     word ptr es:[bx],   0
+    
+    jmp     HEX (F000) : HEX (FFF0)
+
+_config_ok:
+
+    add     sp,     2
+    
+    call    _fclose
+    add     sp,     2
+    
+    mov     cx,     cs:[_menu_entries + 4]
+    
+    and     cx,     cx
+    jnz     .L8
+    
+    call    _error
+    db      "error: no entries found in config file",       HEX (0D),   HEX (0A),   HEX (00)
+
+.L8:
+
+    call    _run_menu
+    
+    push    ds
+    push    es
+    
+    mov     es,     ax
+    xor     bx,     bx
+    
+    mov     ax,     es:[bx + 4]
+    mov     ds,     ax
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Walk the path until we hit the last '/'.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _walk_path
+    jc      _kernel_not_found
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Mangle the file name and search for it in the file system.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _mangle_dos_name
+    jc      _name_error
+    
+    call    _search_dos_dir
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then we couldn't find the specified file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _kernel_not_found
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax register should contain information about the file so
+    ;; copy it into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment as the code segment and copy the value
+    ;; in the ax register into the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The info passed back to us from _search_dos_dir should contain
+    ;; information about the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     es:[bx + 0]
+    mov     cl,     es:[bx + 8]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Was the entry a file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    cl,     HEX (18)
+    jnz      _kernel_not_found
+    
+    pop     es
+    pop     ds
+    jnc     _kernel_open
+
+_name_error:
+
+    pop     bx
+    pop     di
+
+_kernel_not_found:
+
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _error_not_found1
+    call    _writestr
+    
+    pop     ds
+    
+    xor     bx,     bx
+    call    _writestr
+    
+    pop     es
+    pop     ds
+    
+    mov     bx,     offset _error_not_found2
+    call    _writestr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Wait for a keypress.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    int     HEX (16)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Stop floppy motor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     HEX (03F2)
+    xor     al,     al
+    out     dx,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cold reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     bx,     HEX (0472)
+    mov     word ptr es:[bx],   0
+    
+    jmp     HEX (F000) : HEX (FFF0)
+
+_error_not_found1:              db      "error: kernel '",                          HEX (00)
+_error_not_found2:              db      "' not found",      HEX (0D),   HEX (0A),   HEX (00)
+
+_kernel_open:
+
+    mov     di,     cs:[_clustsize]
+    
+    xor     dh,     dh
+    mov     dl,     cs:[_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the number of paragrahs of the memory available.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    mov     cl,     6
+    shl     ax,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract some memory for a stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     HEX (0840) >> 4
+    sub     ax,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the cluster size into paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     di
+    shl     bx
+    shl     bx
+    
+    mov     cl,     4
+    shr     bx,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the segment offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     ax,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store some variable on the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with our calcaulted segment and
+    ;; clear the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    xor     bx,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the cluster into the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the sectors per cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     cs:[_secsperclust]
+    
+    cmp     si,     4
+    jae     .L9
+    
+    mov     si,     4
+
+.L9:
+
+    push    dx
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the cluster into LBA.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    cs:[_convert_cluster]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the sectors per cluster into the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag was set then we've reached the end of the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      .L10
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the cluster into memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _read_sectors
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract the sectors per cluster from our counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     si,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     bx,     cs:[_clustsize]
+    jnc     .L12
+    
+    mov     cx,     es
+    add     ch,     HEX (10)
+    mov     es,     cx
+
+.L12:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the count is zero then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      .L10
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the cluster size to di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     di,     cs:[_clustsize]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get next cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    cs:[_next_cluster]
+    jmp     .L9
+
+.L10:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Figure out how much space is needed for the BPP and the bootstrap
+    ;; code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     offset _bootstrap_len
+    xor     dx,     dx
+    
+    add     ax,     64
+    adc     dx,     0
+    
+    mov     cx,     16
+    div     cx
+    
+    and     dx,     dx
+    jz      _segment_ok2
+    
+    inc     ax
+
+_segment_ok2:
+
+    push    bx
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We want to copy the information just below where we read the
+    ;; cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ds
+    sub     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the value in the bx register
+    ;; and push it to the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the jump.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_fat_jump + 0]
+    stosb
+    
+    mov     ax,     cs:[_fat_jump + 1]
+    stosb
+    
+    mov     ax,     cs:[_fat_jump + 2]
+    stosb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the si register with the address of the BPB info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; As we're mimicking a FAT boot sector we need to make sure
+    ;; di is set to 11 as thats where the BPB actually starts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     11
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy 25 bytes from DS:SI to ES:DI.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're not FAT32 then jump passed the next couple of copies.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     byte ptr [_fat_jump + 1],   HEX (58)
+    jne     .L13
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the sectors per FAT (FAT32 only).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_sectors_per_fat32]
+    stosw
+    
+    mov     ax,     cs:[_sectors_per_fat32 + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Flags and version can just be zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the root cluster (FAT32 only).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_root_cluster]
+    stosw
+    
+    mov     ax,     cs:[_root_cluster + 2]
+    stosw
+
+.L13:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the si register with the address of the bootstrap code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _bootstrap
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the code to the new location.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     offset _bootstrap_len
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call to a help function which restores the interrupts, restores
+    ;; the values on the stack and then jumps to the bootstrap code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _restore_and_jump
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_freeldr_cfg1:                  db      "/boot"
+_freeldr_cfg2:                  db      "/freeldr"
+_freeldr_cfg3:                  db      "/freeldr.cfg",         HEX (00)
+
+_interrupts_list:
+
+    db      HEX (19)
+    dw      _int19_handler
+    dw      HEX (0000)
+    
+    db      HEX (21)
+    dw      _int21_dispatch
+    dw      HEX (0000)
+
+_interrupts_list_end:
diff --git a/src/boot/freeldr/core/int21.asm b/src/boot/freeldr/core/int21.asm
new file mode 100644 (file)
index 0000000..0e5c2c6
--- /dev/null
@@ -0,0 +1,255 @@
+;******************************************************************************
+; @file             int21.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _int21_dispatch
+;******************************************************************************
+global      _int21_dispatch
+_int21_dispatch:
+
+    cld                                                                         ; Make sure direction flag is always clean
+    
+    push    bx
+    push    bp
+    
+    mov     bp,     offset _int21_dispatch.list
+    mov     bx,     offset _int21_dispatch.list_end
+
+_int21_dispatch.L:
+
+    cmp     bp,     bx
+    jae     _int21_dispatch.unimpl
+    
+    cmp     ah,     cs:[bp]
+    jne     _int21_dispatch.next
+    
+    mov     bx,     cs:[bp + 1]
+    
+    mov     bp,     sp
+    xchg    [bp + 2],   bx
+    
+    pop     bp
+    ret
+
+_int21_dispatch.next:
+
+    add     bp,     3
+    
+    cmp     bp,     bx
+    jb      _int21_dispatch.L
+
+_int21_dispatch.unimpl:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    and     dl,     dl
+    jz      _int21_dispatch.col_ok
+    
+    mov     al,     HEX (0D)
+    call    _writechr
+    
+    mov     al,     HEX (0A)
+    call    _writechr
+
+_int21_dispatch.col_ok:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Unimplemented syscall.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _int21_dispatch.err
+    call    _writestr
+    
+    pop     ds
+    pop     ax
+    push    di
+    
+    mov     word ptr [_writehex_num_digits],    2
+    call    _writehex
+    mov     word ptr [_writehex_num_digits],    4
+    
+    pop     di
+    call    _crlf
+    
+    pop     bp
+    pop     bx
+    iret
+
+_int21_dispatch.halt:
+
+    hlt
+    jmp     short   _int21_dispatch.halt
+
+_int21_dispatch.err:
+
+    db      "Not implemented: INT 21h/AH=",     0x00
+
+_int21_dispatch.list:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Open File Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3D)
+    dw      int21_3D
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Close File Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3E)
+    dw      int21_3E
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read From File or Device Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3F)
+    dw      int21_3F
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (48)
+    dw      int21_48
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free Allocated Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (49)
+    dw      int21_49
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Modify Allocated Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4A)
+    dw      int21_4A
+
+_int21_dispatch.list_end:
+
+;******************************************************************************
+; @function         iretc
+;******************************************************************************
+iretc:
+
+    push    bp
+    
+    mov     bp,     sp
+    jc      iretc.c
+    
+    and     byte ptr [bp + 6],  HEX (FE)                                        ; clear carry
+    jmp     short   iretc.ret
+
+iretc.c:
+
+    or      byte ptr [bp + 6],  1                                               ; set carry
+
+iretc.ret:
+
+    pop     bp
+    iret
+
+
+;******************************************************************************
+; @function         int21_3D
+; @brief            Open File Using Handle
+;
+; @in               AL -> Open access mode.
+; @in               DS:DX -> Pointer to an ASCIIZ file name.
+;
+; @out              AX -> File handle.  Error code if CF is set.
+;******************************************************************************
+int21_3D:
+
+    call    _open_file
+    jmp     iretc
+
+;******************************************************************************
+; @function         int21_3E
+; @brief            Close File Using Handle
+;
+; @in               BX -> File handle to close..
+; @out              AX -> Clear.  Error code if CF is set.
+;******************************************************************************
+int21_3E:
+
+    call    _close_file
+    jmp     iretc
+
+;******************************************************************************
+; @function         int21_3F
+; @brief            Read From File or Device Using Handle
+;
+; @in               BX -> File handle..
+; @in               CX -> Number of bytes to read.
+; @in               DS:DX -> Pointer to read buffer.
+;
+; @out              AX -> Number of bytes read.  Error code if CF is set.
+;******************************************************************************
+int21_3F:
+
+    call    _read_file
+    jmp     iretc
+
+;******************************************************************************
+; @function         int21_48
+; @brief            Allocate Memory Blocks
+;
+; @in               BX -> Number of memory paragraphs requested.
+;
+; @out              AX -> Segment address of allocated memory block
+;                         (MCB + lpara).  Error code if CF is set.
+; @out              BX -> Size in paras of the largets block of memory
+;                         available if CF is set and AX = 08 (Not enough mem).
+;******************************************************************************
+int21_48:
+
+    call    _alloc_mem
+    jmp     iretc
+
+;******************************************************************************
+; @function         int21_49
+; @brief            Free Allocated Memeory Blocks
+;
+; @in               ES -> Segment of the block to be returned (MCB + lpara).
+; @out              AX -> Clear.
+;******************************************************************************
+int21_49:
+
+    call    _free_mem
+    jmp     iretc
+
+;******************************************************************************
+; @function         int21_4A
+; @brief            Resize Allocated Memory Blocks
+;
+; @in               BX -> New requested block size in paragraphs.
+; @in               ES -> Segment of block to resize.
+;
+; @out              AX -> Segment address of memory block (MCB + lpara).
+;                         Error code if CF is set.
+; @out              BX -> Set to maximum block size possible if the request
+;                         block size is greater than what available.
+;******************************************************************************
+int21_4A:
+
+    call    _resize_mem
+    jmp     iretc
diff --git a/src/boot/freeldr/core/ll.asm b/src/boot/freeldr/core/ll.asm
new file mode 100644 (file)
index 0000000..c94b283
--- /dev/null
@@ -0,0 +1,691 @@
+;******************************************************************************
+; @file             ll.asm
+;******************************************************************************
+%define     CAPACITY_INCREMENT          256
+
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _load_line
+;******************************************************************************
+global      _load_line
+_load_line:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     12
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     bx,     word ptr [bp + 12]
+    
+    and     bx,     bx
+    jz      .L18
+    
+    mov     cx,     ds
+    
+    push    es
+    push    ds
+    push    si
+    push    di
+    
+    mov     es,     cx
+    mov     ds,     bx
+    
+    mov     di,     offset _load_line_data
+    xor     si,     si
+    
+    mov     cx,     14
+    rep     movsb
+    
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    
+    mov     ax,     ss
+    mov     es,     ax
+    
+    xor     ax,     ax
+    lea     di,     word ptr [bp - 12]
+    
+    mov     cx,     12
+    rep     stosb
+    
+    mov     cx,     word ptr [_load_line_data + 12]
+    
+    and     cx,     cx
+    jz      .L1
+    
+    push    es
+    push    ds
+    
+    mov     ax,     word ptr [_load_line_data + 8]
+    sub     ax,     word ptr [_load_line_data + 12]
+    
+    push    ax
+    
+    mov     ax,     word ptr [_load_line_data + 2]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [_load_line_data + 12]
+    adc     dx,     0
+    
+    div     cx
+    push    dx
+    
+    xor     bx,     bx
+    push    bx
+    
+    mov     bx,     word ptr [_load_line_data + 2]
+    mov     es,     bx
+    
+    mov     ds,     ax
+    
+    call    _memmove
+    add     sp,     6
+    
+    pop     ds
+    pop     es
+    
+    mov     cx,     word ptr [_load_line_data + 12]
+    sub     word ptr [_load_line_data + 8],         cx
+
+.L1:
+
+    mov     ax,     word ptr [_load_line_data + 4]
+    
+    cmp     ax,     word ptr [bp - 12]
+    jb      .L2
+    
+    cmp     ax,     word ptr [bp - 8]
+    ja      .L3
+
+.L2:
+
+    mov     ax,     word ptr [_load_line_data + 4]
+    xor     dx,     dx
+    
+    add     ax,     CAPACITY_INCREMENT
+    mov     word ptr [_load_line_data + 4],         ax
+    
+    mov     bx,     ax
+    xor     cx,     cx
+    
+    add     bx,     2
+    adc     cx,     0
+    
+    push    ax
+    push    dx
+    
+    push    bx
+    push    cx
+    push    word ptr word ptr [_load_line_data + 0]
+    
+    call    _xrealloc
+    add     sp,     6
+    
+    mov     word ptr [_load_line_data + 0],     ax
+    pop     dx
+    pop     ax
+    
+    mov     bx,     ax
+    mov     cx,     dx
+    
+    add     bx,     1
+    adc     cx,     0
+    
+    push    ax
+    push    dx
+    
+    push    bx
+    push    cx
+    push    word ptr word ptr [_load_line_data + 2]
+    
+    call    _xrealloc
+    add     sp,     6
+    
+    mov     word ptr [_load_line_data + 2],     ax
+    pop     dx
+    pop     ax
+
+.L3:
+
+    mov     ax,     word ptr [_load_line_data + 8]
+    
+    cmp     ax,     word ptr [bp - 8]
+    ja      .L4
+
+    push    ds
+    push    word ptr [bp + 10]
+    
+    mov     ax,     word ptr [_load_line_data + 4]
+    sub     ax,     word ptr [bp - 8]
+    
+    push    ax
+    
+    mov     ax,     1
+    push    ax
+    
+    mov     ax,     word ptr [_load_line_data + 2]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [bp - 8]
+    adc     dx,     0
+    
+    div     cx
+    
+    mov     ds,     ax
+    push    dx
+    
+    call    _fread
+    add     sp,     8
+    
+    pop     ds
+    jc      .L5
+    
+    add     ax,     word ptr [bp - 8]
+    mov     word ptr [_load_line_data + 8],     ax
+    
+    mov     ax,     word ptr [_load_line_data + 2]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [_load_line_data + 8]
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    xor     al,     al
+    mov     es:[di],    al
+    
+    pop     di
+    pop     es
+
+.L15:
+
+    cmp     word ptr [bp - 4],      1
+    jne     .L4
+
+.L17:
+
+    mov     ax,     word ptr [_load_line_data + 8]
+    
+    cmp     ax,     word ptr [bp - 8]
+    jb      .L4
+    
+    mov     ax,     word ptr [_load_line_data + 2]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [bp - 8]
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     es:[di]
+    pop     di
+    pop     es
+    
+    cmp     bl,     HEX (0A)
+    jne     .L16
+    
+    mov     word ptr [bp - 4],      0
+    jmp     .L4
+
+.L16:
+
+    add     word ptr [bp - 8],      1
+    jmp     .L17
+
+.L4:
+
+    mov     ax,     word ptr [_load_line_data + 8]
+    
+    cmp     ax,     word ptr [bp - 8]
+    jbe     .L6
+
+.L10:
+
+    mov     ax,     word ptr [_load_line_data + 4]
+    
+    cmp     ax,     word ptr [bp - 12]
+    jbe     .L6
+
+.L11:
+
+    push    es
+    push    di
+    
+    mov     ax,     word ptr [_load_line_data + 2]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [bp - 8]
+    adc     dx,     0
+    
+    div     cx
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     es:[di]
+    pop     di
+    pop     es
+    
+    add     word ptr [bp - 8],      1
+    
+    push    es
+    push    di
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [bp - 12]
+    adc     dx,     0
+    
+    div     cx
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     es:[di],    bl
+    
+    pop     di
+    pop     es
+    
+    cmp     bl,     '#'
+    jne     .L14
+    
+    mov     word ptr [bp - 4],      1
+    jmp     .L15
+
+.L14:
+
+    cmp     bl,     HEX (0A)
+    jne     .L7
+    
+    mov     si,     word ptr [bp - 12]
+    
+    and     si,     si
+    jz      .L12
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     es:[di]
+    pop     di
+    pop     es
+    
+    cmp     bl,     HEX (0D)
+    jne     .L13
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     HEX (0A)
+    mov     es:[di],    bl
+    
+    pop     di
+    pop     es
+    
+    mov     word ptr [bp - 12],     si
+
+.L13:
+
+    and     si,     si
+    jz      .L12
+    
+    dec     si
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     es:[di]
+    pop     di
+    pop     es
+    
+    cmp     bl,     ' '
+    jne     .L12
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     bl,     HEX (0A)
+    mov     es:[di],    bl
+    
+    pop     di
+    pop     es
+    
+    mov     word ptr [bp - 12],     si
+    jmp     .L13
+
+.L12:
+    
+    mov     bx,     word ptr [bp - 12]
+    inc     bx
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     bx
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    xor     al,     al
+    mov     es:[di],    al
+    
+    pop     di
+    pop     es
+    
+    mov     bx,     word ptr [bp - 8]
+    mov     word ptr [_load_line_data + 12],    bx
+    
+    mov     bx,     word ptr [bp + 4]
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    mov     [bx],       ax
+    
+    jmp     .L8
+
+.L7:
+
+    add     word ptr [bp - 12],     1
+    jmp     .L4
+
+.L6:
+
+    push    word ptr [bp + 10]
+    
+    call    _feof
+    add     sp,     2
+    
+    and     ax,     ax
+    jz     .L1
+    
+    mov     cx,     word ptr [_load_line_data + 8]
+    
+    and     cx,     cx
+    jz      .L5
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     word ptr [bp - 12]
+    adc     dx,     0
+    
+    div     cx
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    mov     al,     HEX (0A)
+    mov     es:[di],    al
+    
+    pop     di
+    pop     es
+    
+    mov     bx,     word ptr [bp - 12]
+    inc     bx
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    add     ax,     bx
+    adc     dx,     0
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     dx
+    
+    xor     ax,     ax
+    mov     es:[di],    al
+    
+    pop     di
+    pop     es
+    
+    mov     word ptr [_load_line_data + 12],    ax
+    mov     word ptr [_load_line_data + 8],     ax
+    
+    mov     bx,     word ptr [bp + 4]
+    
+    mov     ax,     word ptr [_load_line_data + 0]
+    mov     [bx],       ax
+    
+    jmp     .L8
+
+.L5:
+
+    mov     ax,     word ptr [bp + 12]
+    mov     es,     ax
+    
+    mov     si,     offset _load_line_data
+    xor     di,     di
+    
+    mov     cx,     14
+    rep     movsb
+
+.L18:
+
+    mov     ax,     1
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     12
+    stc
+    
+    pop     bp
+    ret
+
+.L8:
+
+    mov     ax,     word ptr [bp + 12]
+    mov     es,     ax
+    
+    mov     si,     offset _load_line_data
+    xor     di,     di
+    
+    mov     cx,     14
+    rep     movsb
+    
+    xor     ax,     ax
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     12
+    clc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function          _load_line_create_internal_data
+;******************************************************************************
+global      _load_line_create_internal_data
+_load_line_create_internal_data:
+
+    push    ax
+    push    dx
+
+.L19:
+
+    mov     ax,     16
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+
+.L20:
+
+    pop     dx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function          _load_line_destroy_internal_data
+;******************************************************************************
+global      _load_line_destroy_internal_data
+_load_line_destroy_internal_data:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    es
+    push    bx
+    push    si
+    
+    mov     bx,     word ptr [bp + 4]
+    
+    and     bx,     bx
+    jz      .L21
+    
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     si,     es:[bx + 0]
+    
+    and     si,     si
+    jz      .L22
+    
+    push    si
+    
+    call    _free
+    add     sp,     2
+
+.L22:
+
+    mov     si,     es:[bx + 2]
+    
+    and     si,     si
+    jz      L23
+    
+    push    si
+    
+    call    _free
+    add     sp,     2
+
+L23:
+
+    push    es
+    
+    call    _free
+    add     sp,     2
+
+.L21:
+
+    pop     si
+    pop     bx
+    pop     es
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_load_line_data:                db      14      dup (0)
diff --git a/src/boot/freeldr/core/mangle.asm b/src/boot/freeldr/core/mangle.asm
new file mode 100644 (file)
index 0000000..f3d6e50
--- /dev/null
@@ -0,0 +1,172 @@
+;******************************************************************************
+; @file             mangle.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function        _mangle_dos_name
+;******************************************************************************
+global      _mangle_dos_name
+_mangle_dos_name:
+
+    push    ax
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     cx,     cs
+    mov     es,     cx
+    
+    mov     di,     offset _mangled_name
+    mov     cx,     11
+
+_mangle_dos_name.loop:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jna     _mangle_dos_name.end
+    
+    cmp     al,     '/'
+    je      _mangle_dos_name.end
+    
+    cmp     al,     '.'
+    je      _mangle_dos_name.is_period
+    
+    cmp     al,     HEX (61)
+    jb      _mangle_dos_name.no_conv
+    
+    cmp     al,     HEX (7A)
+    ja      _mangle_dos_name.no_conv
+    
+    mov     dl,     HEX (20)
+    not     dl
+    
+    and     al,     dl
+
+_mangle_dos_name.no_conv:
+
+    mov     bx,     offset _invalid_chars
+    mov     ah,     cl
+    
+    cmp     ax,     HEX (0BE5)
+    jne     _mangle_dos_name.check
+    
+    mov     al,     HEX (05)
+
+_mangle_dos_name.check:
+
+    cmp     byte ptr cs:[bx],   0
+    je      _mangle_dos_name.store
+    
+    cmp     byte ptr cs:[bx],   al
+    je      _mangle_dos_name.error
+    
+    inc     bx
+    jmp     short   _mangle_dos_name.check
+
+_mangle_dos_name.store:
+
+    stosb
+    loop    _mangle_dos_name.loop
+
+_mangle_dos_name.find_end:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jna     _mangle_dos_name.end
+    
+    cmp     al,     '/'
+    jne     _mangle_dos_name.find_end
+
+_mangle_dos_name.end:
+
+    mov     al,     ' '
+    rep     stosb
+
+_mangle_dos_name.done:
+
+    mov     bx,     offset _mangled_name
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    clc
+    ret
+
+_mangle_dos_name.is_period:
+
+    cmp     cx,     11
+    jb      _mangle_dir.period_check
+    
+    mov     al,     '.'
+    stosb
+    
+    dec     cx
+    jmp     _mangle_dos_name.loop
+
+_mangle_dir.period_check:
+
+    cmp     di,     offset _mangled_name
+    je      _mangle_dir.add_period
+    
+    cmp     byte ptr es:[di - 1],   '.'
+    jne     _mangle_dir.need_padding
+
+_mangle_dir.add_period:
+
+    mov     al,     '.'
+    stosb
+    
+    dec     cx
+    jmp     _mangle_dos_name.loop
+
+_mangle_dir.need_padding:
+
+    mov     al,     ' '
+
+_mangle_dos_name.period_loop:
+
+    cmp     cx,     3
+    jbe     _mangle_dos_name.loop
+    
+    stosb
+    loop    _mangle_dos_name.period_loop
+
+_mangle_dos_name.error:
+
+    mov     di,     offset _mangled_name
+    xor     al,     al
+    
+    mov     cx,     11
+    rep     stosb
+    
+    mov     bx,     offset _mangled_name
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    stc
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_invalid_chars:                 db      "\"*+,:;<=>?[\\]|",     HEX (00)
+_mangled_name:                  db      12      dup (0)
diff --git a/src/boot/freeldr/core/mem.asm b/src/boot/freeldr/core/mem.asm
new file mode 100644 (file)
index 0000000..4e28044
--- /dev/null
@@ -0,0 +1,366 @@
+;******************************************************************************
+; @file             mem.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _alloc_mem
+;******************************************************************************
+global      _alloc_mem
+_alloc_mem:
+
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    mov     ax,     cs:[_free_seg]
+    mov     es,     ax
+    
+    push    es
+    
+    mov     ax,     bx
+    xor     di,     di
+
+_alloc_mem.search:
+
+    mov     cx,     es
+    
+    cmp     cx,     cs:[_free_seg]
+    jb      _alloc_mem.error
+    
+    cmp     cx,     cs:[_max_seg]
+    jae     _alloc_mem.error
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _alloc_mem.check
+    
+    jmp     short   _alloc_mem.next
+
+_alloc_mem.check:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _alloc_mem.check2
+    
+    jmp     short   _alloc_mem.next
+
+_alloc_mem.check2:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _alloc_mem.retry
+    
+_alloc_mem.next:
+
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    dec     ax
+    jnz     _alloc_mem.search
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _alloc_mem.check3
+    
+    cmp     si,     cs:[_free_seg]
+    jb      _alloc_mem.error
+    
+    cmp     si,     cs:[_max_seg]
+    jae     _alloc_mem.error
+    
+    jmp     short   _alloc_mem.success
+
+_alloc_mem.check3:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _alloc_mem.check4
+    
+    jmp     short   _alloc_mem.success
+
+_alloc_mem.check4:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _alloc_mem.success
+
+_alloc_mem.retry:
+
+    mov     cx,     es:[di + 3]
+    inc     cx
+    
+    mov     si,     es
+    add     si,     cx
+    mov     es,     si
+    
+    pop     si
+    push    es
+    
+    mov     ax,     bx
+    jmp     _alloc_mem.search
+
+_alloc_mem.success:
+
+    xor     di,     di
+    pop     es
+    
+    mov     byte ptr es:[di],       'M'
+    mov     byte ptr es:[di + 1],   'C'
+    mov     byte ptr es:[di + 2],   'B'
+    
+    mov     word ptr es:[di + 3],   bx
+    ;mov     ax,     cs:[_curr_psp]
+    ;mov     word ptr es:[di + 5],   ax
+    
+    mov     ax,     es
+    inc     ax
+    
+    clc
+    jmp     short   _alloc_mem.done
+
+_alloc_mem.error:
+
+    mov     bx,     es
+    pop     ax
+    sub     bx,     ax
+    
+    mov     ax,     8
+    stc
+
+_alloc_mem.done:
+
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function          _free_mem
+;******************************************************************************
+global      _free_mem
+_free_mem:
+
+    push    bx
+    push    cx
+    push    di
+    push    es
+    
+    mov     di,     es
+    
+    and     di,     di
+    jz      _free_mem.error
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _free_mem.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _free_mem.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _free_mem.error
+    
+    xor     al,     al
+    mov     cx,     16
+    rep     movsb
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     short   _free_mem.done
+    
+_free_mem.error:
+
+    mov     ax,     9
+    stc
+
+_free_mem.done:
+
+    pop     es
+    pop     di
+    pop     cx
+    pop     bx
+    ret
+
+;******************************************************************************
+; @function         _resize_mem
+;******************************************************************************
+global      _resize_mem
+_resize_mem:
+
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    mov     di,     es
+    
+    and     di,     di
+    jz      _resize_mem.error
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _resize_mem.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _resize_mem.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _resize_mem.error
+    
+    mov     cx,     word ptr es:[di + 3]
+    
+    cmp     cx,     bx
+    jae     _resize_mem.success
+    
+    mov     di,     es
+    add     di,     cx
+    mov     es,     di
+    
+    mov     ax,     bx
+    sub     ax,     cx
+    
+    xor     di,     di
+
+_resize_mem.search:
+
+    mov     cx,     es
+    
+    cmp     cx,     cs:[_max_seg]
+    jae     _resize_mem.ins
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _resize_mem.check
+    
+    jmp     short   _resize_mem.next
+
+_resize_mem.check:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _resize_mem.check2
+    
+    jmp     short   _resize_mem.next
+
+_resize_mem.check2:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _resize_mem.ins
+
+_resize_mem.next:
+
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    dec     ax
+    jnz     _resize_mem.search
+    
+    cmp     si,     cs:[_max_seg]
+    jae     _resize_mem.max
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _resize_mem.check3
+    
+    jmp     short   _resize_mem.success
+
+_resize_mem.check3:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _resize_mem.check4
+    
+    jmp     short   _resize_mem.success
+
+_resize_mem.check4:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _resize_mem.ins
+
+_resize_mem.success:
+
+    pop     es
+    
+    mov     di,     es
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    mov     word ptr es:[di + 3],   bx
+    
+    mov     di,     es
+    inc     di
+    mov     es,     di
+    
+    mov     ax,     es
+    clc
+    
+    jmp     short   _resize_mem.done
+
+_resize_mem.max:
+
+    mov     bx,     cs:[_max_seg]
+    jmp     short   _resize_mem.got_seg
+
+_resize_mem.ins:
+
+    mov     bx,     es
+
+_resize_mem.got_seg:
+
+    pop     es
+    
+    mov     ax,     es
+    sub     bx,     ax
+    
+    push    es
+    
+    mov     di,     es
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    mov     word ptr es:[di + 3],   bx
+    
+    mov     ax,     8
+    stc
+    
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+_resize_mem.error:
+
+    mov     ax,     9
+    stc
+    
+    pop     es
+
+_resize_mem.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _free_seg
+_free_seg:                      dw      HEX (0000)
+
+global      _max_seg
+_max_seg:                       dw      HEX (0000)
diff --git a/src/boot/freeldr/core/menu.asm b/src/boot/freeldr/core/menu.asm
new file mode 100644 (file)
index 0000000..36b99c0
--- /dev/null
@@ -0,0 +1,935 @@
+;******************************************************************************
+; @file             menu.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _run_menu_timeout
+;******************************************************************************
+_run_menu_timeout:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    ds
+    
+    mov     dx,     cs:[_menu_timeout]
+    
+    xor     ax,     ax
+    mov     ds,     ax
+    
+    mov     bx,     HEX (046C)
+
+_run_menu_timeout.sec:
+
+    mov     al,     dl
+    aam
+    or      ax,     HEX (3030)
+    
+    mov     cx,     ax
+    push    bx
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _menu_footer1
+    call    _writestr
+    
+    mov     al,     ch
+    call    _writechr
+    
+    mov     al,     cl
+    call    _writechr
+    
+    mov     bx,     offset _menu_footer2
+    
+    cmp     dx,     1
+    jne     _run_menu_timeout.got_secs
+    
+    mov     bx,     offset _menu_footer3
+
+_run_menu_timeout.got_secs:
+
+    call    _writestr
+    
+    cmp     dx,     1
+    jne     _run_menu_timeout.check
+    
+    xor     al,     al
+    call    _writechr
+
+_run_menu_timeout.check:
+
+    mov     al,     HEX (0D)
+    call    _writechr
+    
+    pop     ds
+    pop     bx
+    clc
+    
+    dec     dx
+    js      _run_menu_timeout.done
+    
+    mov     cx,     HEX (12)
+
+_run_menu_timeout.tick:
+
+    mov     si,     [bx]
+
+_run_menu_timeout.wait:
+
+    stc
+    
+    mov     ah,     HEX (01)
+    int     HEX (16)
+    jnz     _run_menu_timeout.done
+    
+    cmp     si,     [bx]
+    je      _run_menu_timeout.wait
+    
+    loop    _run_menu_timeout.tick
+    jmp     short   _run_menu_timeout.sec
+
+_run_menu_timeout.done:
+
+    pop     ds
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _convert_entry
+;******************************************************************************
+_convert_entry:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    es
+    push    ds
+    
+    mov     ax,     cs:[_menu_entry_list]
+    
+    and     ax,     ax
+    jz      _convert_entry.init
+    
+    push    es
+    push    di
+    
+    mov     es,     ax
+    mov     di,     cs:[_list_idx]
+    
+    mov     al,     ','
+    stosb
+    
+    mov     cs:[_list_idx],     di
+    
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     es
+
+_convert_entry.init:
+
+    mov     ax,     word ptr [bp + 4]
+    mov     es,     ax
+    xor     bx,     bx
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_video_cols]
+    
+    inc     cx
+    sub     cx,     8
+    
+    xor     dx,     dx
+    
+_convert_entry.check:
+
+    mov     ax,     es:[bx + 2]
+    mov     ds,     ax
+    xor     si,     si
+    
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    cmp     ax,     cx
+    jbe     _convert_entry.length_ok
+    
+    mov     ax,     cx
+
+_convert_entry.length_ok:
+
+    push    cx
+    push    ax
+    push    bx
+    push    es
+    
+    mov     ax,     cs:[_menu_entry_list]
+    mov     es,     ax
+    xor     bx,     bx
+    
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    pop     es
+    pop     bx
+    pop     ax
+    
+    add     ax,     cx
+    adc     dx,     0
+    pop     cx
+    
+    add     ax,     2
+    adc     dx,     0
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     cs:[_menu_entry_list]
+    push    ax
+    
+    call    _xrealloc
+    add     sp,     6
+    
+    mov     cs:[_menu_entry_list],      ax
+    
+    mov     es,     ax
+    mov     di,     cs:[_list_idx]
+
+_convert_entry.loop:
+
+    and     cx,     cx
+    jz      _convert_entry.done
+    
+    lodsb
+    
+    or      al,     al
+    jz      _convert_entry.done
+    
+    stosb
+    
+    dec     cx
+    jmp     short   _convert_entry.loop
+
+_convert_entry.done:
+
+    mov     cs:[_list_idx],     di
+    
+    xor     al,     al
+    stosb
+    
+    pop     ds
+    pop     es
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _move_cursor
+;******************************************************************************
+_move_cursor:
+
+    push    ax
+    push    bx
+    
+    mov     ah,     HEX (02)
+    xor     bl,     bl
+    int     HEX (10)
+    
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _draw_black_bar
+;******************************************************************************
+_draw_black_bar:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+
+_draw_black_bar.move:
+
+    mov     dl,     3
+    call    _move_cursor
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_video_cols]
+    
+    inc     cx
+    sub     cx,     3
+
+_draw_black_bar.draw:
+
+    mov     ax,     HEX (0920)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_draw_black_bar.done:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _draw_white_bar
+;******************************************************************************
+_draw_white_bar:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+
+_draw_white_bar.move:
+
+    mov     dl,     HEX (03)
+    call    _move_cursor
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_video_cols]
+    
+    inc     cx
+    sub     cx,     6
+
+_draw_white_bar.draw:
+
+    mov     ax,     HEX (0920)
+    mov     bx,     HEX (0070)
+    int     HEX (10)
+
+_draw_white_bar.done:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _hide_cursor
+;******************************************************************************
+_hide_cursor:
+
+    push    ax
+    push    cx
+    
+    mov     ax,     HEX (0103)
+    mov     ch,     32
+    int     HEX (10)
+    
+    pop     cx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _show_cursor
+;******************************************************************************
+_show_cursor:
+
+    push    ax
+    push    cx
+    
+    mov     ax,     HEX (0103)
+    mov     cx,     HEX (0607)
+    int     HEX (10)
+    
+    pop     cx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _draw_list
+;******************************************************************************
+_draw_list:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    mov     dx,     HEX (0204)
+    call    _move_cursor
+    
+    mov     cx,     word ptr [bp + 6]
+    mov     si,     word ptr [bp + 4]
+    
+    mov     di,     word ptr [bp + 8]
+    dec     di
+
+_draw_list.skip_loop:
+
+    and     cx,     cx
+    jz      _draw_list.skip_loop_finished
+
+_draw_list.more_lodsb:
+
+    lodsb
+    
+    cmp     al,     ','
+    jne     _draw_list.more_lodsb
+    
+    dec     cx
+    jmp     _draw_list.skip_loop
+
+_draw_list.skip_loop_finished:
+
+    xor     bx,     bx
+
+_draw_list.more:
+
+    lodsb
+    
+    and     al,     al
+    jz      _draw_list.done
+    
+    cmp     al,     ','
+    je      _draw_list.newline
+    
+    call    _writechr
+    jmp     _draw_list.more
+
+_draw_list.newline:
+
+    mov     dl,     HEX (04)
+    
+    inc     dh
+    call    _move_cursor
+    
+    inc     bx
+    
+    cmp     bx,     di
+    jl      _draw_list.more
+
+_draw_list.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    call    _move_cursor
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _draw_menu
+;******************************************************************************
+_draw_menu:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     12
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    xor     cx,     cx
+    mov     si,     ax
+    
+    mov     word ptr [bp - 6],      ax
+    
+    xor     ah,     ah
+    mov     al,     cs:[_video_rows]
+    
+    shr     ax
+    mov     word ptr [bp - 12],     ax
+    
+    xor     ax,     ax
+    mov     word ptr [bp - 8],      ax
+    
+    call    _hide_cursor
+
+_draw_menu.count_loop:
+
+    lodsb
+    
+    and     al,     al
+    jz      _draw_menu.done_count
+    
+    cmp     al,     ','
+    jne     _draw_menu.count_loop
+    
+    inc     cx
+    jmp     _draw_menu.count_loop
+
+_draw_menu.done_count:
+
+    inc     cx
+    
+    mov     word ptr [bp - 4],      cx
+    mov     word ptr [bp - 2],      0
+    
+    xor     ax,     ax
+    mov     word ptr [bp - 10],     0
+    
+    mov     dx,     HEX (0204)
+    call    _move_cursor
+    
+    push    ax
+    push    bx
+    push    cx
+    
+    mov     ax,     cs:[_menu_default]
+    
+    mov     cx,     word ptr [bp - 12]
+    sub     cx,     2
+    
+    cmp     ax,     cx
+    ja      _draw_menu.calc_skip
+    
+    add     dh,     al
+    jmp     _draw_menu.got_default
+
+_draw_menu.calc_skip:
+
+    mov     dh,     cl
+    add     dh,     2
+    
+    sub     ax,     cx
+    
+    mov     word ptr [bp - 2],      ax
+
+_draw_menu.got_default:
+
+    pop     cx
+    pop     bx
+    pop     ax
+
+_draw_menu.more_select:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ax,     word ptr [bp - 12]
+    mov     dh,     al
+    
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    mov     cx,     HEX (0200)
+    mov     dl,     HEX (50)
+    int     HEX (10)
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    call    _draw_white_bar
+    
+    push    word ptr [bp - 12]
+    push    word ptr [bp - 2]
+    push    word ptr [bp - 6]
+    
+    call    _draw_list
+    add     sp,     6
+    
+_draw_menu.check:
+
+    cmp     word ptr [bp - 8],      0
+    jne     _draw_menu.get_key
+
+_draw_menu.timeout:
+
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     cx,     word ptr [bp - 4]
+    
+    mov     bx,     word ptr [bp - 12]
+    dec     bx
+    
+    cmp     cx,     bx
+    jb      _draw_menu.adjust
+    
+    mov     cx,     bx
+
+_draw_menu.adjust:
+
+    inc     cx
+    
+    mov     dh,     HEX (02)
+    add     dh,     cl
+    
+    xor     dl,     dl
+    call    _move_cursor
+    
+    mov     ax,     dx
+    call    _run_menu_timeout
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    jnc     _draw_menu.option_selected
+    
+    mov     word ptr [bp - 8],      1
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     dx,     ax
+    call    _move_cursor
+    
+    mov     ax,     HEX (0920)
+    mov     bx,     HEX (0007)
+    mov     cx,     HEX (0050)
+    int     HEX (10)
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    call    _move_cursor
+
+_draw_menu.get_key:
+
+    xor     ah,     ah
+    int     HEX (16)
+    
+    cmp     ah,     HEX (48)
+    je      _draw_menu.go_up
+    
+    cmp     ah,     HEX (50)
+    je      _draw_menu.go_down
+    
+    cmp     al,     HEX (0D)
+    je      _draw_menu.option_selected
+    
+    jmp     _draw_menu.get_key
+
+_draw_menu.go_up:
+
+    cmp     dh,     HEX (02)
+    jle     _draw_menu.hit_top
+    
+    call    _draw_black_bar
+    
+    mov     dl,     HEX (04)
+    call    _move_cursor
+    
+    dec     dh
+    jmp     _draw_menu.more_select
+
+_draw_menu.go_down:
+
+    mov     ax,     word ptr [bp - 12]
+    
+    cmp     dh,     al
+    je      _draw_menu.hit_bottom
+    
+    xor     ch,     ch
+    mov     cl,     dh
+    
+    sub     cl,     HEX (02)
+    inc     cl
+    add     cx,     word ptr [bp - 2]
+    
+    mov     ax,     word ptr [bp - 4]
+    
+    cmp     cx,     ax
+    je      _draw_menu.get_key
+    
+    call    _draw_black_bar
+    
+    mov     dl,     HEX (04)
+    call    _move_cursor
+    
+    inc     dh
+    jmp     _draw_menu.more_select
+
+_draw_menu.hit_top:
+
+    mov     cx,     word ptr [bp - 2]
+    
+    and     cx,     cx
+    jz      _draw_menu.get_key
+    
+    dec     word ptr [bp - 2]
+    jmp     _draw_menu.more_select
+
+_draw_menu.hit_bottom:
+
+    xor     ch,     ch
+    mov     cl,     dh
+    
+    sub     cl,     HEX (02)
+    inc     cl
+    add     cx,     word ptr [bp - 2]
+    
+    mov     ax,     word ptr [bp - 4]
+    
+    cmp     cx,     ax
+    je      _draw_menu.get_key
+    
+    inc     word ptr [bp - 2]
+    jmp     _draw_menu.more_select
+
+_draw_menu.option_selected:
+
+    sub     dh,     HEX (02)
+    
+    xor     ah,     ah
+    mov     al,     dh
+    
+    inc     ax
+    add     ax,     word ptr [bp - 2]
+
+_draw_menu.done:
+
+    call    _show_cursor
+    
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     12
+    clc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _run_menu
+;******************************************************************************
+global      _run_menu
+_run_menu:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     8
+    
+    push    bx
+    push    cx
+    push    es
+    push    ds
+    push    di
+    
+    mov     cx,     cs:[_menu_timeout]
+    
+    and     cx,     cx
+    jnz     _run_menu.init
+    
+    mov     ax,     cs:[_menu_default]
+    inc     ax
+    
+    jmp     _run_menu.done
+
+_run_menu.init:
+
+    mov     ax,     cs:[_menu_default]
+    mov     word ptr [bp - 6],      ax
+    
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 2],      0
+
+_run_menu.clear:
+
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    xor     cx,     cx
+    mov     dh,     cs:[_video_rows]
+    mov     dl,     cs:[_video_cols]
+    int     HEX (10)
+
+_run_menu.reset:
+
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+
+_run_menu.display_title:
+
+    mov     ax,     HEX (0920)
+    mov     bx,     HEX (0070)
+    
+    xor     ch,     ch
+    
+    mov     cl,     cs:[_video_cols]
+    inc     cl
+    
+    int     HEX (10)
+    
+    mov     ah,     HEX (03)
+    xor     bh,     bh
+    int     HEX (10)
+    
+    mov     ax,     offset _menu_header
+    push    ax
+    
+    call    _strlen
+    add     sp,     2
+    
+    push    dx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    div     cx
+    
+    mov     bx,     ax
+    
+    xor     ah,     ah
+    mov     al,     cs:[_video_cols]
+    
+    add     ax,     cx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    div     cx
+    
+    pop     dx
+    
+    sub     al,     bl
+    add     dl,     al
+    
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    int     HEX (10)
+    
+    mov     bx,     offset _menu_header
+    call    _writestr
+    
+    xor     dl,     dl
+    
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    int     HEX (10)
+
+_run_menu.init2:
+
+    mov     bx,     offset _menu_entries
+    
+    mov     ax,     [bx + 0]
+    mov     cx,     [bx + 4]
+    
+    mov     es,     ax
+    xor     bx,     bx
+
+_run_menu.convert:
+
+    mov     ax,     es:[bx]
+    push    ax
+    
+    call    _convert_entry
+    add     sp,     2
+    
+    add     word ptr [bp - 4],      1
+    add     bx,     2
+    
+    loop    _run_menu.convert
+    
+    mov     ax,     cs:[_menu_entry_list]
+    mov     ds,     ax
+    
+    xor     ax,     ax
+    call    _draw_menu
+
+_run_menu.done:
+
+    push    ax
+    
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    xor     cx,     cx
+    mov     dh,     cs:[_video_rows]
+    mov     dl,     cs:[_video_cols]
+    int     HEX (10)
+    
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+    
+    pop     ax
+    
+    mov     bx,     cs:[_menu_entries]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    xor     dx,     dx
+    dec     ax
+    
+    mov     cx,     2
+    mul     cx
+    
+    add     bx,     ax
+    mov     ax,     es:[bx]
+    
+    pop     di
+    pop     ds
+    pop     es
+    pop     cx
+    pop     bx
+    
+    add     sp,     8
+    clc
+    
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_menu_entry_list:               dw      HEX (0000)
+_list_idx:                      dw      HEX (0000)
+
+_menu_header:                   db      "Freeldr Boot Manager",         HEX (00)
+
+_menu_footer1:                  db      " Automatically booting in ",   HEX (00)
+_menu_footer2:                  db      " seconds...",                  HEX (00)
+_menu_footer3:                  db      " second...",                   HEX (00)
+
+global      _menu_default
+_menu_default:                  dw      HEX (0000)
+
+global      _menu_timeout
+_menu_timeout:                  dw      HEX (0000)
+
+global      _menu_entries
+_menu_entries:                  db      HEX (0006)      dup (0)
diff --git a/src/boot/freeldr/core/screen.asm b/src/boot/freeldr/core/screen.asm
new file mode 100644 (file)
index 0000000..7d054e6
--- /dev/null
@@ -0,0 +1,80 @@
+;******************************************************************************
+; @file             screen.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _adjust_screen
+;******************************************************************************
+global      _adjust_screen
+_adjust_screen:
+
+    push    ax
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment wit zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try to get the amount of rows from the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [HEX (0484)]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Did the BIOS contain the rows?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Yep, so we're good.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _adjust_screen.vidrows_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so we'll assume 25.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     HEX (18)
+
+_adjust_screen.vidrows_ok:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the amount of rows the console has.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cs:[_video_rows],       al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the video state.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0F)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ah register contains the amount of columns the console has.  We
+    ;; need to subtract by one as indexing starts at zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     ah
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the amount of columns the console has.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cs:[_video_cols],       ah
+
+_adjust_screen.done:
+
+    pop     ds
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _video_rows
+_video_rows:                    db      HEX (00)
+
+global      _video_cols
+_video_cols:                    db      HEX (00)
diff --git a/src/boot/freeldr/core/search.asm b/src/boot/freeldr/core/search.asm
new file mode 100644 (file)
index 0000000..75583f8
--- /dev/null
@@ -0,0 +1,259 @@
+;******************************************************************************
+; @file             search.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc file for our BPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _search_dos_dir
+;******************************************************************************
+global      _search_dos_dir
+_search_dos_dir:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     34
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 32],     bx
+    
+    mov     word ptr [bp - 20],     0
+    mov     word ptr [bp - 16],     0
+    
+    mov     bx,     ax
+    or      bx,     dx
+    
+    and     bx,     bx
+    jnz     _search_dos_dir.not_root
+    
+    mov     ax,     cs:[_root_start]
+    mov     dx,     cs:[_root_start + 2]
+
+_search_dos_dir.got_root:
+
+    mov     word ptr [bp - 30],     1
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    mov     ax,     32
+    xor     dx,     dx
+    
+    mov     cx,     cs:[_root_entries]
+    mul     cx
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    div     cx
+    
+    xchg    cx,     ax
+    dec     cx
+    
+    xor     dx,     dx
+    mov     word ptr [bp - 22],     cx
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.not_root:
+
+    mov     word ptr [bp - 30],     0
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    call    cs:[_convert_cluster]
+    jc      _search_dos_dir.not_found
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    mov     word ptr [bp - 34],     bx
+
+_search_dos_dir.read:
+
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    mov     cx,     word ptr [bp - 24]
+    call    _read_sectors
+    
+    mov     ax,     cs:[_bytes_per_sector]
+    xor     dx,     dx
+    
+    mov     cx,     32
+    div     cx
+    xchg    cx,     ax
+    
+    xor     di,     di
+
+_search_dos_dir.search:
+
+    push    cx
+    mov     cx,     11
+    
+    cmp     byte ptr es:[di],       0
+    je      _search_dos_dir.advance
+    
+    cmp     byte ptr es:[di],       HEX (E5)
+    je      _search_dos_dir.advance
+    
+    push    si
+    push    di
+    push    ds
+    
+    mov     si,     cs
+    mov     ds,     si
+    
+    mov     si,     word ptr [bp - 32]
+    repe    cmpsb
+    
+    pop     ds
+    pop     di
+    pop     si
+    je      _search_dos_dir.found
+
+_search_dos_dir.advance:
+
+    pop     cx
+    
+    add     di,     32
+    loop    _search_dos_dir.search
+    
+    cmp     word ptr [bp - 30],     1
+    jne     _search_dos_dir.check
+    
+    mov     ax,     word ptr [bp - 22]
+    
+    and     ax,     ax
+    jz      _search_dos_dir.not_found
+    
+    dec     ax
+    mov     word ptr [bp - 22],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.check:
+
+    mov     ax,     word ptr [bp - 34]
+    
+    and     ax,     ax
+    jz      _search_dos_dir.next_clust
+    
+    dec     ax
+    mov     word ptr [bp - 34],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.next_clust:
+
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    call    cs:[_next_cluster]
+    jmp     _search_dos_dir.not_root
+
+_search_dos_dir.not_found:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     34
+    pop     bp
+    
+    mov     ax,     3
+    stc
+    
+    ret
+
+_search_dos_dir.found:
+
+    pop     cx
+    mov     si,     di
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    mov     bx,     offset _file_info
+    
+    mov     ax,     es:[di + 26]
+    mov     [bx + 0],   ax
+    
+    mov     ax,     es:[di + 20]
+    mov     [bx + 2],   ax
+    
+    mov     ax,     es:[di + 28]
+    mov     [bx + 4],   ax
+    
+    mov     ax,     es:[di + 30]
+    mov     [bx + 6],   ax
+    
+    mov     al,     es:[di + 11]
+    mov     [bx + 8],   al
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     34
+    pop     bp
+    
+    mov     ax,     offset _file_info
+    clc
+    
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_file_info:                     db      9       dup (0)
diff --git a/src/boot/freeldr/core/vector.asm b/src/boot/freeldr/core/vector.asm
new file mode 100644 (file)
index 0000000..2b3988b
--- /dev/null
@@ -0,0 +1,142 @@
+;******************************************************************************
+; @file             vector.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _vec_adjust
+;******************************************************************************
+_vec_adjust:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_adjust.check:
+
+    mov     cx,     [bx + 2]
+    
+    cmp     cx,     word ptr [bp + 6]
+    ja      _vec_adjust.done
+
+_vec_adjust.check2:
+
+    and     cx,     cx
+    jnz     _vec_adjust.shift
+    
+    mov     cx,     16
+    jmp     short   _vec_adjust.set
+
+_vec_adjust.shift:
+
+    shl     cx
+
+_vec_adjust.set:
+
+    mov     [bx + 2],   cx
+
+_vec_adjust.alloc:
+
+    mov     ax,     2
+    xor     dx,     dx
+    
+    mul     cx
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     [bx + 0]
+    push    ax
+    
+    call    _xrealloc
+    add     sp,     6
+    
+    mov     [bx + 0],       ax
+
+_vec_adjust.done:
+
+    xor     ax,     ax
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _vec_push
+;******************************************************************************
+global      _vec_push
+_vec_push:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_push.alt:
+
+    mov     ax,     [bx + 4]
+    push    ax
+    
+    push    word ptr [bp + 4]
+    
+    call    _vec_adjust
+    add     sp,     4
+    
+    mov     word ptr [bp - 2],      ax
+    
+    and     ax,     ax
+    jnz     _vec_push.done
+
+_vec_push.set:
+
+    mov     ax,     [bx + 0]
+    mov     es,     ax
+    
+    mov     ax,     [bx + 4]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     di,     ax
+    
+    mov     ax,     [bp + 6]
+    mov     es:[di],    ax
+    
+    mov     cx,     [bx + 4]
+    add     cx,     1
+    
+    mov     [bx + 4],   cx
+
+_vec_push.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    pop     bp
+    
+    ret
diff --git a/src/boot/freeldr/core/walk.asm b/src/boot/freeldr/core/walk.asm
new file mode 100644 (file)
index 0000000..e3db99c
--- /dev/null
@@ -0,0 +1,98 @@
+;******************************************************************************
+; @file             walk.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _walk_path
+;******************************************************************************
+global      _walk_path
+_walk_path:
+
+    push    bx
+    
+    mov     ax,     cs:[_root_cluster]
+    mov     dx,     cs:[_root_cluster + 2]
+    
+    xor     cx,     cx
+    
+    cmp     byte ptr [di],      '/'
+    jne     _walk_path.not_root
+    
+    inc     di
+
+_walk_path.not_root:
+
+    push    ax
+    push    dx
+    
+    mov     si,     di
+
+_walk_path.find_end:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jbe     _walk_path.end_path
+    
+    cmp     al,     '/'
+    jne     _walk_path.find_end
+
+_walk_path.end_path:
+
+    xchg    si,     di
+    pop     dx
+    pop     ax
+    
+    mov     bx,     di
+    dec     bx
+    
+    cmp     bx,     si
+    je      _walk_path.done
+    
+    cmp     byte ptr [di - 1],      0
+    je      _walk_path.done
+    
+    call    _mangle_dos_name
+    jc      _walk_path.not_found
+    
+    call    _search_dos_dir
+    jc      _walk_path.not_found
+    
+    push    bx
+    push    es
+    
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    mov     ax,     es:[bx + 0]
+    mov     dx,     es:[bx + 2]
+    
+    mov     cl,     es:[bx + 8]
+    pop     es
+    pop     bx
+    
+    test    cl,     HEX (10)
+    jz      _walk_path.not_found
+    
+    cmp     byte ptr [di - 1],      '/'
+    jne     _walk_path.done
+    
+    jmp     _walk_path.not_root
+
+_walk_path.not_found:
+
+    pop     bx
+    stc
+    
+    ret
+
+_walk_path.done:
+
+    pop     bx
+    clc
+    
+    ret
diff --git a/src/boot/freeldr/core/writechr.asm b/src/boot/freeldr/core/writechr.asm
new file mode 100644 (file)
index 0000000..b268990
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             writechr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         writechr
+;******************************************************************************
+global      _writechr
+_writechr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    bp                                                                  ; Some BIOSes destroy BP when the screen scrolls
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/boot/freeldr/core/writedec.asm b/src/boot/freeldr/core/writedec.asm
new file mode 100644 (file)
index 0000000..bd97d47
--- /dev/null
@@ -0,0 +1,53 @@
+;******************************************************************************
+; @file             writedec.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writedec
+;******************************************************************************
+global      _writedec
+_writedec:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    bp
+    
+    mov     bx,     10
+    xor     cx,     cx
+
+_writedec.cloop:
+
+    div     bx
+    inc     cx
+    
+    push    dx
+    xor     dx,     dx
+    
+    and     ax,     ax
+    jnz     _writedec.cloop
+
+_writedec.dloop:
+
+    pop     ax
+    
+    mov     ah,     HEX (0E)
+    add     al,     '0'
+    int     HEX (10)
+    
+    loop    _writedec.dloop
+
+_writedec.done:
+
+    pop     bp
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/boot/freeldr/core/writehex.asm b/src/boot/freeldr/core/writehex.asm
new file mode 100644 (file)
index 0000000..2b0eba7
--- /dev/null
@@ -0,0 +1,70 @@
+;******************************************************************************
+; @file             writehex.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+global      _writehex
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     cs:[_writehex_num_digits]
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (0E)
+    
+    push    bp
+    push    bx
+    
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     bp
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _writehex_num_digits
+_writehex_num_digits:           dw      HEX (0004)
diff --git a/src/boot/freeldr/core/writestr.asm b/src/boot/freeldr/core/writestr.asm
new file mode 100644 (file)
index 0000000..a849e2e
--- /dev/null
@@ -0,0 +1,75 @@
+;******************************************************************************
+; @file             writestr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _writestr
+;******************************************************************************
+global      _writestr
+_writestr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    si
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize si with bx
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump over our printing code to get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _writestr.next
+
+_writestr.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_writestr.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _writestr.print
+
+_writestr.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     si
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/boot/freeldr/core/xmalloc.asm b/src/boot/freeldr/core/xmalloc.asm
new file mode 100644 (file)
index 0000000..cb56c1e
--- /dev/null
@@ -0,0 +1,118 @@
+;******************************************************************************
+; @file             xmalloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _xmalloc
+;******************************************************************************
+global      _xmalloc
+_xmalloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [bp + 6]
+    mov     dx,     [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call malloc.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    call    _malloc
+    add     sp,     4
+    
+    jc      _xmalloc.error
+    
+    push    ax
+    push    bx
+    
+    dec     ax
+    mov     es,     ax
+    
+    xor     bx,     bx
+    mov     cx,     es:[bx + 3]
+    
+    pop     bx
+    pop     ax
+    
+    push    ax
+    mov     es,     ax
+
+_xmalloc.loop:
+
+    xor     di,     di
+    
+    push    ax
+    push    cx
+    
+    xor     al,     al
+    mov     cx,     16
+    rep     stosb
+    
+    pop     cx
+    pop     ax
+    
+    inc     ax
+    mov     es,     ax
+    
+    loop    _xmalloc.loop
+
+_xmalloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_xmalloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we fail to get memory in here then there's something wrong
+    ;; so just error out.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "Memory full (malloc)",     HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/boot/freeldr/core/xrealloc.asm b/src/boot/freeldr/core/xrealloc.asm
new file mode 100644 (file)
index 0000000..1443176
--- /dev/null
@@ -0,0 +1,94 @@
+;******************************************************************************
+; @file             xrealloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _xrealloc
+;******************************************************************************
+global      _xrealloc
+_xrealloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [bp + 8]
+    mov     dx,     [bp + 6]
+    mov     si,     [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call realloc.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    push    si
+    
+    call    _realloc
+    add     sp,     6
+    
+    and     ax,     ax
+    jz      _xrealloc.error
+
+_xrealloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_xrealloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we fail to get memory in here then there's something wrong
+    ;; so just error out.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "Memory full (realloc)",    HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/boot/freeldr/freeldr.cfg b/src/boot/freeldr/freeldr.cfg
new file mode 100644 (file)
index 0000000..2cf568e
--- /dev/null
@@ -0,0 +1,7 @@
+default     chimaera
+#timeout     10
+timeout     0
+
+label chimaera
+    title   Chimaera OS
+    kernel  /kernel.sys
diff --git a/src/boot/freeldr/genhash.c b/src/boot/freeldr/genhash.c
new file mode 100644 (file)
index 0000000..8cacbc4
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+ * @file            genhash.c
+ *****************************************************************************/
+#include    <ctype.h>
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <string.h>
+
+struct hash {
+
+    char *keywd;
+    unsigned value;
+    
+    struct hash *next;
+    struct hash **prev;
+
+};
+
+static char *trim_whitespace (char *str) {
+
+    char *end;
+    
+    while (isspace ((int) *str)) {
+        str++;
+    }
+    
+    if (*str == '\0') {
+        return str;
+    }
+    
+    end = str + strlen (str) - 1;
+    
+    while (end > str && isspace ((int) *end)) {
+        end--;
+    }
+    
+    end[1] = '\0';
+    return str;
+
+}
+
+static void hash_push (struct hash **head, struct hash *item) {
+
+    item->prev = head;
+    
+    if (*head) {
+        (*head)->prev = &item->next;
+    }
+    
+    item->next = *head;
+    *head = item;
+
+}
+
+int main (int argc, char **argv) {
+
+    struct hash *curr_hash, *seen_hashes = 0;
+    
+    char ch, keywd[256], *p;
+    unsigned hash;
+    
+    while ((fgets (keywd, sizeof (keywd), stdin))) {
+    
+        p = trim_whitespace (keywd);
+        hash = 0;
+        
+        while ((ch = *p++)) {
+            hash = (((hash << 5) | (hash >> 11)) ^ (ch | 0x20)) & 0xffff;
+        }
+        
+        for (curr_hash = seen_hashes; curr_hash; curr_hash = curr_hash->next) {
+        
+            if (curr_hash->value == hash) {
+            
+                fprintf (stderr, "hash collision (0x%04x) %s %s\n", hash, keywd, curr_hash->keywd);
+                return 1;
+            
+            }
+        
+        }
+        
+        if (!(curr_hash = (struct hash *) malloc (sizeof (*curr_hash)))) {
+        
+            fprintf (stderr, "Out of memory");
+            return 1;
+        
+        }
+        
+        curr_hash->keywd = keywd;
+        curr_hash->value = hash;
+        
+        curr_hash->next = 0;
+        hash_push (&seen_hashes, curr_hash);
+        
+        printf ("hash_%s: equ 0x%04x\n", keywd, hash);
+    
+    }
+    
+    return 0;
+
+}
diff --git a/src/boot/freeldr/keywords b/src/boot/freeldr/keywords
new file mode 100644 (file)
index 0000000..d5fda1b
--- /dev/null
@@ -0,0 +1,6 @@
+default
+kernel
+label
+root
+timeout
+title
diff --git a/src/boot/freeldr/libc/Makefile.unix b/src/boot/freeldr/libc/Makefile.unix
new file mode 100644 (file)
index 0000000..b3b5803
--- /dev/null
@@ -0,0 +1,35 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  stdio stdlib string
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: libc.a
+
+clean:
+       for f in `find . -name '*.o'`; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in `find . -name '*.lst'`; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       if [ -f libc.a ]; then rm -rf libc.a; fi
+
+libc.a: stdio/fclose.o stdio/feof.o stdio/fopen.o stdio/fread.o stdlib/free.o stdlib/malloc.o stdlib/realloc.o string/memmove.o string/strlen.o
+       ../../../utils/binutils/sar r libc.a $^
+       ../../../utils/binutils/sar s libc.a
+
+stdio/%.o: stdio/%.asm
+       if [ ! -d "stdio" ]; then mkdir -p "stdio"; fi
+       ../../../utils/binutils/sasm -I$(SRCDIR)/include -l stdio/$*.lst -o $@ $<
+
+stdlib/%.o: stdlib/%.asm
+       if [ ! -d "stdlib" ]; then mkdir -p "stdlib"; fi
+       ../../../utils/binutils/sasm -l stdlib/$*.lst -o $@ $<
+
+string/%.o: string/%.asm
+       if [ ! -d "string" ]; then mkdir -p "string"; fi
+       ../../../utils/binutils/sasm -l string/$*.lst -o $@ $<
+
+%.o: %.asm
+       ../../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/boot/freeldr/libc/Makefile.w32 b/src/boot/freeldr/libc/Makefile.w32
new file mode 100644 (file)
index 0000000..d4f502c
--- /dev/null
@@ -0,0 +1,35 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  stdio stdlib string
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: libc.a
+
+clean:
+       for /r %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for /r %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+       if exist libc.a ( del /q libc.a )
+
+libc.a: stdio/fclose.o stdio/feof.o stdio/fopen.o stdio/fread.o stdlib/free.o stdlib/malloc.o stdlib/realloc.o string/memmove.o string/strlen.o
+       ../../../utils/binutils/sar r libc.a $^
+       ../../../utils/binutils/sar s libc.a
+
+stdio/%.o: stdio/%.asm
+       if not exist "stdio" ( mkdir "stdio" )
+       ../../../utils/binutils/sasm -I$(SRCDIR)/include -l stdio/$*.lst -o $@ $<
+
+stdlib/%.o: stdlib/%.asm
+       if not exist "stdlib" ( mkdir "stdlib" )
+       ../../../utils/binutils/sasm -l stdlib/$*.lst -o $@ $<
+
+string/%.o: string/%.asm
+       if not exist "string" ( mkdir "string" )
+       ../../../utils/binutils/sasm -l string/$*.lst -o $@ $<
+
+%.o: %.asm
+       ../../../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/boot/freeldr/libc/stdio/fclose.asm b/src/boot/freeldr/libc/stdio/fclose.asm
new file mode 100644 (file)
index 0000000..27bcbed
--- /dev/null
@@ -0,0 +1,90 @@
+;******************************************************************************
+; @file             fclose.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fclose
+;******************************************************************************
+global      _fclose
+_fclose:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actaully have some value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _fclose.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    xor     si,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es:[si]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=3E to close the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (3E)
+    int     HEX (21)
+    jc      _fclose.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free our pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    word ptr [bp + 4]
+    
+    call    _free
+    add     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
+
+_fclose.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/stdio/feof.asm b/src/boot/freeldr/libc/stdio/feof.asm
new file mode 100644 (file)
index 0000000..7ca588d
--- /dev/null
@@ -0,0 +1,92 @@
+;******************************************************************************
+; @file             feof.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _feof
+;******************************************************************************
+global      _feof
+_feof:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actaully have some value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _feof.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    xor     si,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the flags from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es:[si + 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached EOF?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     HEX (0100)
+    jz      _feof.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return 1 to indicate that we reached EOF.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1
+
+_feof.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
+
+_feof.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/stdio/fopen.asm b/src/boot/freeldr/libc/stdio/fopen.asm
new file mode 100644 (file)
index 0000000..32dc079
--- /dev/null
@@ -0,0 +1,129 @@
+;******************************************************************************
+; @file             fopen.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fopen
+;******************************************************************************
+global      _fopen
+_fopen:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=3D to open the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ax,     HEX (3D00)
+    int     HEX (21)
+    jc      _fopen.error
+
+_fopen.success:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the file handle in ax.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate some memory for a pointer (i.e. FILE *).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     16
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _xmalloc
+    add     sp,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the malloc didn't fail.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     ax
+    jz      _fopen.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll use es:di to store the values.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We're not handling files (at least so far) so just push a null word.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We're not EOF yet.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in the extra segment into ax.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fopen.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/stdio/fread.asm b/src/boot/freeldr/libc/stdio/fread.asm
new file mode 100644 (file)
index 0000000..a59e3e1
--- /dev/null
@@ -0,0 +1,209 @@
+;******************************************************************************
+; @file             fread.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fread
+;******************************************************************************
+global      _fread
+_fread:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the reserved stack value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the buffer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have actually buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;and     si,     si
+    ;jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 10]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the amount of bytes to read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the number of bytes are zero then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     cx,     cx
+    jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    mov     dx,     es:[di + 2]
+    
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached the end of the file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    dx,     HEX (0100)
+    jnz     _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the number of bytes into the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the dx register with the address of the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read # no of bytes into the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (3F)
+    int     HEX (21)
+    jc      _fread.error
+    
+    and     ax,     ax
+    jnz     _fread.read_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add an EOF marker to the flags,
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    or      word ptr es:[di + 2],       HEX (0100)
+    pop     di
+    pop     es
+    
+    jmp     short   _fread.zero
+
+_fread.read_ok:
+
+    cmp     cx,     ax
+    je      _fread.size_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add an EOF marker to the flags,
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    or      word ptr es:[di + 2],       HEX (0100)
+    pop     di
+    pop     es
+
+_fread.size_ok:
+
+    cmp     word ptr [bp + 6],      0
+    je      _fread.zero
+    
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    div     cx
+    
+    mov     word ptr [bp - 2],      ax
+    jmp     _fread.done
+
+_fread.zero:
+
+    mov     word ptr [bp - 2],      0
+
+_fread.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fread.error:
+
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/stdlib/free.asm b/src/boot/freeldr/libc/stdlib/free.asm
new file mode 100644 (file)
index 0000000..d165740
--- /dev/null
@@ -0,0 +1,37 @@
+;******************************************************************************
+; @file             free.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _free
+;******************************************************************************
+global      _free
+_free:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=49 to free the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (49)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     ax
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/stdlib/malloc.asm b/src/boot/freeldr/libc/stdlib/malloc.asm
new file mode 100644 (file)
index 0000000..bebd0ec
--- /dev/null
@@ -0,0 +1,90 @@
+;******************************************************************************
+; @file             malloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _malloc
+;******************************************************************************
+global      _malloc
+_malloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 6]
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the size to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _malloc.ok
+
+_malloc.inc:
+
+    inc     ax
+    jz      _malloc.error
+
+_malloc.ok:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=48 to allocate the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    
+    mov     ah,     HEX (48)
+    int     HEX (21)
+    jc      _malloc.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_malloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/boot/freeldr/libc/stdlib/realloc.asm b/src/boot/freeldr/libc/stdlib/realloc.asm
new file mode 100644 (file)
index 0000000..2e43b97
--- /dev/null
@@ -0,0 +1,233 @@
+;******************************************************************************
+; @file             realloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _realloc
+;******************************************************************************
+global      _realloc
+_realloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    si
+    push    di
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack as well as the pointer to
+    ;; re-allocate.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    mov     dx,     word ptr [bp + 6]
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have valid memory as a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _realloc.calc
+    
+    mov     di,     bx
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _realloc.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _realloc.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _realloc.error
+
+_realloc.calc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the size to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _realloc.ok
+
+_realloc.inc:
+
+    inc     ax
+    jz      _realloc.error
+
+_realloc.ok:
+
+    mov     si,     ax
+    
+    and     bx,     bx
+    jz      _realloc.alloc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First. lets try and resize the memory block.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    mov     es,     bx
+    mov     bx,     si
+    
+    mov     ah,     HEX (4A)
+    int     HEX (21)
+    pop     es
+    pop     bx
+    jnc     _realloc.done
+
+_realloc.alloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=48 to allocate the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    mov     bx,     si
+    
+    mov     ah,     HEX (48)
+    int     HEX (21)
+    pop     bx
+    jc      _realloc.error
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Only copy existing data if there was an original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     bx
+    
+    and     di,     di
+    jz      _realloc.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers that copy will clobber.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ds
+    
+    mov     di,     bx
+    mov     ds,     di
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    mov     cx,     word ptr es:[di + 3]
+    mov     es,     ax
+    
+    cmp     cx,     bx
+    jb      _realloc.copy
+    
+    mov     cx,     bx
+
+_realloc.copy:
+
+    xor     si,     si
+    xor     di,     di
+    
+    push    cx
+    
+    mov     cx,     16
+    rep     movsb
+    
+    pop     cx
+    
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    mov     di,     ds
+    inc     di
+    mov     ds,     di
+    
+    loop    _realloc.copy
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers that copy clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     si
+
+_realloc.free:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we reached this point then free the original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    
+    mov     ah,     HEX (49)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_realloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_realloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/boot/freeldr/libc/string/memmove.asm b/src/boot/freeldr/libc/string/memmove.asm
new file mode 100644 (file)
index 0000000..ec8cb39
--- /dev/null
@@ -0,0 +1,91 @@
+;******************************************************************************
+; @file             memmove.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _memmove
+;******************************************************************************
+global      _memmove
+_memmove:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    si
+    push    di
+    push    bx
+    push    cx
+    
+    mov     di,     word ptr [bp + 4]
+    mov     si,     word ptr [bp + 6]
+    mov     cx,     word ptr [bp + 8]
+
+.L3:
+
+    cmp     di,     si
+    ja      .L2
+
+.L4:
+
+    and     cx,     cx
+    jz      .L1
+    
+    movsb
+    dec     cx
+    
+    jmp     .L4
+    
+    jmp     .L1
+
+.L2:
+
+    and     cx,     cx
+    jz      .L1
+    
+    dec     cx
+
+.L6:
+
+    and     cx,     cx
+    jz      .L5
+    
+    mov     bx,     si
+    add     bx,     cx
+    
+    mov     al,     [si]
+    
+    mov     bx,     di
+    add     bx,     cx
+    
+    mov     es:[di],    al
+    
+    dec     cx
+    jmp     .L6
+
+.L5:
+
+    mov     bx,     si
+    add     bx,     cx
+    
+    mov     al,     [si]
+    
+    mov     bx,     di
+    add     bx,     cx
+    
+    mov     es:[di],    al
+
+.L1:
+
+    pop     cx
+    pop     bx
+    pop     di
+    pop     si
+    
+    mov     ax,     word ptr [bp + 4]
+    clc
+    
+    pop     bp
+    ret
diff --git a/src/boot/freeldr/libc/string/strlen.asm b/src/boot/freeldr/libc/string/strlen.asm
new file mode 100644 (file)
index 0000000..273730b
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             strlen.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strlen
+;******************************************************************************
+global      _strlen
+_strlen:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    cx
+    push    si
+    push    di
+    
+    mov     si,     word ptr [bp + 4]
+    xor     cx,     cx
+
+_strlen.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strlen.done
+    
+    inc     cx
+    jmp     short   _strlen.loop
+
+_strlen.done:
+
+    mov     ax,     cx
+    
+    pop     di
+    pop     si
+    pop     cx
+    pop     bp
+    ret
diff --git a/src/boot/mbr/Makefile.unix b/src/boot/mbr/Makefile.unix
new file mode 100644 (file)
index 0000000..578342b
--- /dev/null
@@ -0,0 +1,16 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: dosmbr.bin
+
+clean:
+       if [ -f dosmbr.bin ]; then rm -rf dosmbr.bin; fi
+       if [ -f dosmbr.lst ]; then rm -rf dosmbr.lst; fi
+
+%.bin: %.asm
+       ../../utils/binutils/sasm -f bin -l $*.lst -o $@ $<
diff --git a/src/boot/mbr/Makefile.w32 b/src/boot/mbr/Makefile.w32
new file mode 100644 (file)
index 0000000..2fb6aa3
--- /dev/null
@@ -0,0 +1,16 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: dosmbr.bin
+
+clean:
+       if exist dosmbr.bin ( del /q dosmbr.bin )
+       if exist dosmbr.lst ( del /q dosmbr.lst )
+
+%.bin: %.asm
+       ../../utils/binutils/sasm -f bin -l $*.lst -o $@ $<
diff --git a/src/boot/mbr/dosmbr.asm b/src/boot/mbr/dosmbr.asm
new file mode 100644 (file)
index 0000000..33374ca
--- /dev/null
@@ -0,0 +1,331 @@
+;******************************************************************************
+; @file             dosmbr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy ourselves down to memory address 0000:0600.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (07C0)
+    mov     ds,     ax
+    
+    mov     ax,     HEX (0060)
+    mov     es,     ax
+    
+    xor     si,     si
+    xor     di,     di
+    
+    mov     cx,     256
+    rep     movsw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Now jump to the copy.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     HEX (0060) : _real_start
+
+;******************************************************************************
+; @function         _real_start
+;******************************************************************************
+_real_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     ss,     ax
+    mov     sp,     HEX (0600)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the di register with the address of the first
+    ;; partition information.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (01BE)
+    
+    .test_for_active:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Is the partition active?
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        test        byte ptr [di],      HEX (80)
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Yes, so lets try boot from it.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jnz     .active_partition_found
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Advance to the next partition entry.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        add     di,     HEX (0010)
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Have we reached the end of the partition table?
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        cmp     di,     HEX (01FE)
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Nope, so check this partition.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jb      .test_for_active
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; We haven't found an active partition.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        call    error
+        db      "No active partition found",    HEX (0D),   HEX (0A),   HEX (00)
+    
+    .active_partition_found:
+    
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Load the boot sector from the partition.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        call    read_boot_sector
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; If the carry flag is set then the read was unsuccessful.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jc      .trouble_reading_drive
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Is the partition bootable?
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        cmp     word ptr es:[HEX (7DFE)],   HEX (AA55)
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Nope, so we'll just print out an error.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jne     .invalid_partition_code
+        
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        ;; Finally, jump to the boot code.
+        ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+        jmp     HEX (0000) : HEX (7C00)
+    
+    .trouble_reading_drive:
+    
+        call    error
+        db      "Read error while reading drive",   HEX (0D),   HEX (0A),   HEX (00)
+    
+    .invalid_partition_code:
+    
+        call    error
+        db      "Partition signature != 55AA",      HEX (0D),   HEX (0A),   HEX (00)
+
+;******************************************************************************
+; @function          error
+;******************************************************************************
+error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the address of the string from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump passed printing so that we get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   error.next
+
+error.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ah register with 'Teletype output'.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the bx register with the 'Page number' and 'Color'.
+    ;;
+    ;;   Note: The color isn't used unless where in graphics mode
+    ;;         but it may be best practice to set it anyway.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     HEX (0007)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (10)
+
+error.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     error.print
+
+error.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Wait for a keypress then warm reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    int     HEX (16)
+    int     HEX (19)
+
+;******************************************************************************
+; @function         read_boot_sector
+;******************************************************************************
+read_boot_sector:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (41)
+    mov     bx,     HEX (55AA)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then disk extensions a unavailable.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      read_boot_sector.standard_bios
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Bit 1 in the cx register should be set if disk extensions
+    ;; are present.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    shr     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Test for carry (from shr) too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sbb     bx,     HEX (AA55) - 1
+    jne     read_boot_sector.standard_bios
+
+read_boot_sector.lba_bios:
+
+    mov     ax,     [di + 8]
+    mov     [read_boot_sector.bios_lba_low],    ax
+    
+    mov     ax,     [di + 10]
+    mov     [read_boot_sector.bios_lba_high],   ax
+    
+    mov     ax,     HEX (4200)
+    mov     si,     offset read_boot_sector.bios_lba_address_packet
+    
+    stc
+    int     HEX (13)
+    ret
+
+read_boot_sector.standard_bios:
+
+    mov     ax,     HEX (0204)
+    mov     bx,     HEX (7C00)
+    mov     cx,     [di + 2]
+    mov     dh,     [di + 1]
+    
+    stc
+    int     HEX (13)
+    ret
+
+read_boot_sector.bios_lba_address_packet:
+
+    db      HEX (10)
+    db      HEX (00)
+    dw      HEX (0004)
+    dw      HEX (7C00)
+    dw      HEX (0000)
+
+read_boot_sector.bios_lba_low:
+
+    dw      HEX (0000)
+
+read_boot_sector.bios_lba_high:
+
+    dw      HEX (0000)
+    dw      HEX (0000),     HEX (0000)
+
+;******************************************************************************
+; @function          writehex
+;******************************************************************************
+writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    di
+    
+    mov     cl,     4
+    mov     di,     4
+
+writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     writehex.high
+
+writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   writehex.ischar
+
+writehex.high:
+
+    add     al,     HEX (37)
+
+writehex.ischar:
+
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     ax
+    
+    dec     di
+    jnz     writehex.loop
+
+writehex.done:
+
+    pop     di
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Pad with zeros until 440 bytes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+db  HEX (01B8) - (. - _start)   dup (0)
diff --git a/src/kernel/Makefile.unix b/src/kernel/Makefile.unix
new file mode 100644 (file)
index 0000000..8be5e8a
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: kernel.sys
+
+clean:
+       for f in *.o; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in *.lst; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       if [ -f kernel.sys ]; then rm -rf kernel.sys; fi
+
+kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o find.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
+       ../utils/binutils/slink --oformat binary -o $@ $^
+
+%.o: %.asm
+       ../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/kernel/Makefile.w32 b/src/kernel/Makefile.w32
new file mode 100644 (file)
index 0000000..d444a13
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+all: kernel.sys
+
+clean:
+       for %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+       if exist kernel.sys ( del /q kernel.sys )
+
+kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
+       ../utils/binutils/slink --oformat binary -o $@ $^
+
+%.o: %.asm
+       ../utils/binutils/sasm -l $*.lst -o $@ $<
diff --git a/src/kernel/bootstrap.asm b/src/kernel/bootstrap.asm
new file mode 100644 (file)
index 0000000..28231f0
--- /dev/null
@@ -0,0 +1,1327 @@
+;******************************************************************************
+; @file             bootstrap.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Memory layout.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+Mem.Stack.Top:                  equ     HEX (0840)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Define some offsets for the BPB.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _bytes_per_sector           (bp - 64)
+%define     _sectors_per_cluster        (bp - 62)
+%define     _reserved_sectors           (bp - 61)
+%define     _number_of_fats             (bp - 59)
+%define     _root_entries               (bp - 58)
+%define     _total_sectors16            (bp - 56)
+%define     _media_descriptor           (bp - 54)
+%define     _sectors_per_fat            (bp - 53)
+%define     _sectors_per_track          (bp - 51)
+%define     _heads_per_cylinder         (bp - 49)
+%define     _hidden_sectors             (bp - 47)
+%define     _total_sectors32            (bp - 43)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; FAT32 EBPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _sectors_per_fat32          (bp - 39)
+%define     _root_cluster               (bp - 35)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Other offsets used within this file.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _edd_available              (bp - 28)
+%define     _drive_no                   (bp - 26)
+
+%define     _fat_start                  (bp - 24)
+%define     _data_start                 (bp - 20)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; FAT32 offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _fat_secmask                (bp - 16)
+%define     _fat_secshift               (bp - 14)
+%define     _fat_sector                 (bp - 12)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Offsets of FAT12 and FAT16 convert cluster and next cluster functions.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _convert_cluster            (bp - 8)
+%define     _next_cluster               (bp - 6)
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and cx register as well as the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    es
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the convertional memory (in KBs) ...
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; ... And convert it into 16-byte paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     6
+    shl     ax,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reserve memory for a stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     (Mem.Stack.Top >> 4)
+    sub     ax,     cx
+    
+    mov     di,     ax
+    
+    popf
+    pop     es
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    mov     ss,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base and stack pointers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     Mem.Stack.Top
+    lea     sp,     [bp - 64]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no. passed to us.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, bx, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Transfer the drive no. into the dl register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     cl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure our edd_avaiable variable is zero by default.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [_edd_available],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Only check if we're booted from a hard disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    dl,     HEX (70)
+    jnz     _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (41)
+    mov     bx,     HEX (55AA)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then disk extensions a unavailable.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Bit 1 in the cx register should be set if disk extensions
+    ;; are present.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    shr     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Test for carry (from shr) too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sbb     bx,     HEX (AA55) - 1
+    jne     _no_edd
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indicate that we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [_edd_available],      1
+
+_no_edd:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, bx, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    popf
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the extra segment and si register as they
+    ;; get clobbered by movsb.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    si
+    pushf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB just above the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     ss
+    mov     es,     di
+    
+    mov     si,     11
+    lea     di,     [bp - 64]
+    
+    mov     cx,     25
+    rep     movsb
+    
+    cmp     byte ptr [HEX (01)],    HEX (58)
+    jne     _not_fat32
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we get here then we're dealing with FAT32, so first
+    ;; preserve the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the number of sectors per FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [HEX (24)]
+    stosw
+    
+    mov     ax,     [HEX (26)]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the root cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [HEX (2C)]
+    stosw
+    
+    mov     ax,     [HEX (2E)]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    di
+    push    ax
+    push    dx
+
+_calc_offsets:
+
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     [_hidden_sectors]
+    mov     di,     [_hidden_sectors + 2]
+    
+    add     si,     [_reserved_sectors]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_fat_start],       si
+    mov     [_fat_start + 2],       di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [_number_of_fats]
+    cbw
+    
+    push    ax
+    
+    mul     word ptr [_sectors_per_fat32 + 2]
+    add     di,     ax
+    
+    pop     ax
+    mul     word ptr [_sectors_per_fat32]
+    
+    add     ax,     si
+    adc     dx,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_data_start],      ax
+    mov     [_data_start + 2],      dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    pop     di
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [_bytes_per_sector]
+    shr     ax
+    shr     ax
+    dec     ax
+    
+    mov     [_fat_secmask],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+    xchg    ax,     cx
+
+_secshift:
+
+    inc     ax
+    shr     cx
+    
+    cmp     cx,     1
+    jne     _secshift
+    
+    mov     [_fat_secshift],        ax
+    dec     cx
+    
+    mov     [_fat_sector],      cx
+    mov     [_fat_sector + 2],      cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_after_copy:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    popf
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers (need as _next_cluster pops both).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L6
+
+.L4:
+
+    push    dx
+    push    ax
+    push    bx
+    
+    call    _convert_cluster32
+    jc      .L7
+    
+    mov     cx,     bx
+    pop     bx
+
+.L5:
+
+    call    _read_sectors
+
+.L6:
+
+    pop     ax
+    pop     dx
+    
+    call    _nextcluster_fat32
+    jmp     short   .L4
+
+.L7:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     ax
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the value in the bx register to a segment and add
+    ;; it to the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     4
+    shr     bx,     cl
+    
+    mov     cx,     es
+    add     cx,     bx
+    mov     es,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Pass the drive no. in dl.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dh,     dh
+    mov     dl,     [_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     bx,     bx
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to the main code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _all_read
+
+;******************************************************************************
+; @function         _not_fat32
+;******************************************************************************
+_not_fat32:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    ax
+    push    dx
+    
+    xor     ax,     ax
+    
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     [_hidden_sectors]
+    mov     di,     [_hidden_sectors + 2]
+    
+    add     si,     [_reserved_sectors]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset ready for the fathelper at the start of
+    ;; freeldr.sys.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_fat_start],       si
+    mov     [_fat_start + 2],       di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [_number_of_fats]
+    cbw
+    mul     word ptr [_sectors_per_fat]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the FAT offset to get the root directory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors the root directory requires.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0020)
+    mul     word ptr [_root_entries]
+    div     word ptr [_bytes_per_sector]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the root offset to get the data offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_data_start],      si
+    mov     [_data_start + 2],      di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    pop     di
+    
+    popf
+    pop     si
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Previded we've got a clean stack, the carry flag should be set from
+    ;; the boot sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      .L3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the address of the next cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _getfattype
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers (need as _next_cluster pops both).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L1
+
+.L2:
+
+    push    dx
+    push    ax
+    push    bx
+    
+    call    [_convert_cluster]
+    jc      .L3
+    
+    mov     cx,     bx
+    pop     bx
+
+.L8:
+
+    push    bp
+    push    ax
+    push    bx
+    
+    mov     ax,     HEX (0E2E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     ax
+    pop     bp
+    call    _read_sectors
+
+.L1:
+
+    pop     ax
+    pop     dx
+    
+    call    [_next_cluster]
+    jmp     short   .L2
+
+.L3:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the screen.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (07)
+    xor     cx,     cx
+    mov     dx,     HEX (184F)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the cursor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     ax
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the value in the bx register to a segment and add
+    ;; it to the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     4
+    shr     bx,     cl
+    
+    mov     cx,     es
+    add     cx,     bx
+    mov     es,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Pass the drive no. in dl.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dh,     dh
+    mov     dl,     [_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     bx,     bx
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to the main code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _all_read
+
+;******************************************************************************
+; @function         _convert_cluster12
+;******************************************************************************
+_convert_cluster12:
+
+    cmp     ax,     HEX (0FF8)
+    jb      _convert_cluster12.c3
+    
+    stc
+    ret
+
+_convert_cluster12.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [_data_start]
+    add     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster16
+;******************************************************************************
+_convert_cluster16:
+
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster16.c3
+    
+    stc
+    ret
+
+_convert_cluster16.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     [_data_start]
+    add     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster32
+;******************************************************************************
+_convert_cluster32:
+
+    cmp     dx,     HEX (0FFF)
+    jne     _convert_cluster32.c3
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster32.c3
+    
+    stc
+    ret
+
+_convert_cluster32.c3:
+
+    mov     cx,     dx
+    
+    sub     ax,     2
+    sbb     cx,     0
+    
+    mov     bl,     [_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    xchg    cx,     ax
+    mul     bx
+    
+    xchg    ax,     cx
+    mul     bx
+    
+    add     dx,     cx
+    
+    add     ax,     [_data_start]
+    add     dx,     [_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _getfattype
+;******************************************************************************
+_getfattype:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    xor     ax,     ax
+
+_getfattype.init:
+
+    mov     al,     [_sectors_per_cluster]
+    cbw
+    mov     si,     ax
+    
+    mov     di,     [_bytes_per_sector]
+    
+    xor     dx,     dx
+    xor     cx,     cx
+    
+    mov     ax,     [_total_sectors16]
+    and     ax,     ax
+    jnz     _getfattype.have_secs
+    
+    mov     ax,     [_total_sectors32]
+    mov     dx,     [_total_sectors32 + 2]
+
+_getfattype.have_secs:
+
+    sub     ax,     [_reserved_sectors]
+    sbb     dx,     0
+    
+    mov     cl,     [_number_of_fats]
+
+_getfattype.sec_fat_loop:
+
+    sub     ax,     [_sectors_per_fat]
+    sbb     dx,     0
+    loop    _getfattype.sec_fat_loop
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     [_root_entries]
+    mov     bx,     32
+    mul     bx
+    
+    add     ax,     di
+    adc     dx,     0
+    
+    sub     ax,     1
+    sbb     dx,     0
+    
+    div     di
+    mov     bx,     ax
+    
+    pop     dx
+    pop     ax
+    
+    sub     ax,     bx
+    sbb     dx,     0
+    
+    div     si
+    
+    cmp     ax,     4096
+    ja      _getfattype.fat16
+
+_getfattype.fat12:
+
+    mov     ax,     offset _convert_cluster12
+    mov     [_convert_cluster],     ax
+    
+    mov     ax,     offset _nextcluster_fat12
+    mov     [_next_cluster],        ax
+    
+    jmp     short   _getfattype.done
+
+_getfattype.fat16:
+
+    mov     ax,     offset _convert_cluster16
+    mov     [_convert_cluster],     ax
+    
+    mov     ax,     offset _nextcluster_fat16
+    mov     [_next_cluster],        ax
+
+_getfattype.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat12
+;******************************************************************************
+_nextcluster_fat12:
+
+    push    cx
+    push    si
+    
+    mov     si,     ax
+
+_nextcluster_fat12.secoff:
+
+    mov     ax,     3
+    mul     si
+    shr     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat12.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     [_fat_start]
+    mov     dx,     [_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat12.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat12.cn_exit
+
+_nextcluster_fat12.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat12.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat12.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    push    ds
+    mov     ax,     ss
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+    jnc     _nextcluster_fat12.even_cluster
+    
+    mov     cl,     4
+    shr     ax,     cl
+
+_nextcluster_fat12.even_cluster:
+
+    and     ax,     HEX (0FFF)
+
+_nextcluster_fat12.compare:
+
+    cmp     ax,     HEX (0FF8)
+    cmc
+
+_nextcluster_fat12.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat16
+;******************************************************************************
+_nextcluster_fat16:
+
+    push    cx
+    push    si
+
+_nextcluster_fat16.secoff:
+
+    shl     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     [_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat16.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     [_fat_start]
+    mov     dx,     [_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat16.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat16.cn_exit
+
+_nextcluster_fat16.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat16.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat16.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    mov     ax,     ss
+    jnc     _nextcluster_fat16.first64
+    
+    add     ax,     HEX (1000)
+
+_nextcluster_fat16.first64:
+
+    push    ds
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+
+_nextcluster_fat16.compare:
+
+    cmp     ax,     HEX (FFF8)
+    cmc
+
+_nextcluster_fat16.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat32
+;******************************************************************************
+_nextcluster_fat32:
+
+    push    es
+    push    bx
+    push    cx
+    push    di
+    
+    mov     di,     ax
+    and     di,     [_fat_secmask]
+    
+    mov     cx,     [_fat_secshift]
+
+_nextcluster_fat32.cn_loop:
+
+    shr     dx
+    rcr     ax
+    loop    _nextcluster_fat32.cn_loop
+    
+    shl     di
+    shl     di
+    
+    add     ax,     [_fat_start]
+    adc     dx,     [_fat_start + 2]
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    cmp     ax,     [_fat_sector]
+    jne     _nextcluster_fat32.read
+    
+    cmp     dx,     [_fat_sector + 2]
+    je      _nextcluster_fat32.cn_exit
+
+_nextcluster_fat32.read:
+
+    mov     [_fat_sector],      ax
+    mov     [_fat_sector + 2],      dx
+    
+    mov     cx,     1
+    call    _read_sectors
+
+_nextcluster_fat32.cn_exit:
+
+    mov     ax,     es:[di]
+    mov     dx,     es:[di + 2]
+    
+    cmp     dx,     HEX (0FFF)
+    jne     _nextcluster_fat32.no_carry
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _nextcluster_fat32.no_carry
+    
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    stc
+    ret
+
+_nextcluster_fat32.no_carry:
+
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    clc
+    ret
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    di
+
+_read_sectors.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The di regsiter will be our retry counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (0005)
+
+_read_sectors.retry:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If disk extensions aren't avaiable then we need to use CHS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr [_edd_available],       1
+    jb      _read_sectors.chs
+
+_read_sectors.lba:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll create the LBA read on the stack.  8086 doesn't allow pushing
+    ;; values directly so we'll use si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    push    si
+    push    si
+    
+    push    dx
+    push    ax
+    push    es
+    push    bx
+    
+    mov     si,     1
+    push    si
+    
+    mov     si,     16
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The dl register needs to be set to the drive number before we alter
+    ;; the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     [_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need to set si to sp as the LBA read requires ds:si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment to the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ss
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (42)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cleanup the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was no carry the we successfully read the sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnc     _read_sectors.success
+
+_read_sectors.chs:
+
+    div     word ptr [_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA # SPT        = sector - 1
+    
+    mov     cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr [_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) # HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    ror     ah
+    ror     ah
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     [_drive_no]
+    stc
+    int     HEX (13)
+    jnc     _read_sectors.success
+
+_read_sectors.failure:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     dl,     [_drive_no]
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the loop counter and retry if greater than zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     di
+    jnz     _read_sectors.retry
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    add     bx,     [_bytes_per_sector]
+    jnc     _read_sectors.no_incr
+    
+    mov     cx,     es
+    add     ch,     HEX (10)
+    mov     es,     cx
+
+_read_sectors.no_incr:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop until cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _read_sectors.next
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     4
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (0E)
+    
+    push    bp
+    push    bx
+    
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     bp
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Make sure we fit inside 2048 bytes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+db      HEX (0800) - (. - _start)   dup (0)
diff --git a/src/kernel/crlf.asm b/src/kernel/crlf.asm
new file mode 100644 (file)
index 0000000..b715115
--- /dev/null
@@ -0,0 +1,33 @@
+;******************************************************************************
+; @file             crlf.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _crlf
+;******************************************************************************
+global      _crlf
+_crlf:
+
+    push    ax
+    push    bx
+    push    dx
+    push    bp
+    
+    mov     ah,     HEX (0E)
+    mov     al,     HEX (0D)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    mov     ah,     HEX (0E)
+    mov     al,     HEX (0A)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bp
+    pop     dx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/kernel/disk.asm b/src/kernel/disk.asm
new file mode 100644 (file)
index 0000000..64fba99
--- /dev/null
@@ -0,0 +1,983 @@
+;******************************************************************************
+; @file             disk.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc file for our BPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _read_boot_sector
+;******************************************************************************
+_read_boot_sector:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have disk extensions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (41)
+    mov     bx,     HEX (55AA)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then disk extensions a unavailable.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _read_boot_sector.standard_bios
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Bit 1 in the cx register should be set if disk extensions
+    ;; are present.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    shr     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Test for carry (from shr) too.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sbb     bx,     HEX (AA55) - 1
+    jne     _read_boot_sector.standard_bios
+
+_read_boot_sector.lba_bios:
+
+    mov     cs:[_read_boot_sector.bios_lba_address_packet + 6],      es
+    
+    mov     ax,     es:[si + 8]
+    mov     cs:[_read_boot_sector.bios_lba_low],     ax
+    
+    mov     ax,     es:[si + 10]
+    mov     cs:[_read_boot_sector.bios_lba_high],    ax
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     ax,     HEX (4200)
+    mov     si,     offset _read_boot_sector.bios_lba_address_packet
+    
+    stc
+    int     HEX (13)
+    
+    jmp     _read_boot_sector.check
+
+_read_boot_sector.standard_bios:
+
+    mov     ax,     HEX (0201)
+    xor     bx,     bx
+    
+    mov     cx,     es:[si + 2]
+    mov     dh,     es:[si + 1]
+    
+    stc
+    int     HEX (13)
+
+_read_boot_sector.check:
+
+    cmp     byte ptr es:[bx],   HEX (EB)
+    je      _read_boot_sector.check2
+    
+    stc
+    jmp     _read_boot_sector.done
+
+_read_boot_sector.check2:
+
+    cmp     byte ptr es:[bx + 2],   HEX (90)
+    je      _read_boot_sector.done
+    
+    stc
+
+_read_boot_sector.done:
+
+    pop     ds
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+_read_boot_sector.bios_lba_address_packet:
+
+    db      HEX (10)
+    db      HEX (00)
+    db      HEX (01)
+    db      HEX (00)
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+_read_boot_sector.bios_lba_low:
+
+    dw      HEX (0000)
+
+_read_boot_sector.bios_lba_high:
+
+    dw      HEX (0000)
+    dw      HEX (0000),     HEX (0000)
+
+;******************************************************************************
+; @function         _get_partition_info
+;******************************************************************************
+global      _get_partition_info
+_get_partition_info:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the base pointer to the stack pointer and reserve some space.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     24
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    ds
+    push    bx
+    push    si
+    push    di
+    push    dx
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the stack space.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 6],      0
+    mov     word ptr [bp - 8],      0
+    mov     word ptr [bp - 10],     0
+    mov     word ptr [bp - 12],     0
+    mov     word ptr [bp - 14],     0
+    mov     word ptr [bp - 16],     0
+    mov     word ptr [bp - 18],     0
+    mov     word ptr [bp - 20],     0
+    mov     word ptr [bp - 22],     0
+    mov     word ptr [bp - 24],     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; MBR partitions start at offset 0x01BE and are 16 bytes in length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 6]
+    xor     dx,     dx
+    
+    mov     cx,     16
+    mul     cx
+    
+    mov     si,     ax
+    add     si,     HEX (01BE)
+
+.L8:
+
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (10)
+    stc
+    int     HEX (13)
+    jc      .L21
+
+.L9:
+
+    push    cx
+    push    dx
+    
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     HEX (0201)
+    mov     cx,     HEX (0001)
+    xor     dh,     dh
+    stc
+    int     HEX (13)
+    
+    pop     dx
+    pop     cx
+    jc      .L21
+
+.L10:
+
+    cmp     byte ptr es:[bx + 0],       HEX (EB)
+    jne     .L11
+    
+    cmp     byte ptr es:[bx + 2],       HEX (90)
+    jne     .L11
+    
+    jmp     .L12
+
+.L11:
+
+    cmp     byte ptr es:[si],       128
+    je      .L13
+    
+    cmp     byte ptr es:[si],       0
+    jne     .L21
+
+.L13:
+
+    xor     ch,     ch
+    mov     cl,     cs:[_drive_no]
+    
+    cmp     word ptr [bp + 4],      cx
+    jne     .L23
+    
+    cmp     byte ptr es:[si],       128
+    jne     .L23
+    
+    mov     word ptr [bp - 2],      1
+
+.L23:
+
+    mov     bx,     ss
+    mov     es,     bx
+    xor     bx,     bx
+    
+    call    _read_boot_sector
+    jc      .L21
+
+.L14:
+
+    cmp     byte ptr es:[bx + 0],       HEX (EB)
+    jne     .L21
+    
+    cmp     byte ptr es:[bx + 2],       HEX (90)
+    jne     .L21
+    
+    cmp     byte ptr es:[bx + 1],       HEX (58)
+    jne     .L12
+    
+    mov     ax,     es:[bx + 44]
+    mov     dx,     es:[bx + 46]
+    
+    mov     word ptr [bp - 4],      ax
+    mov     word ptr [bp - 6],      dx
+    
+    xor     ax,     ax
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     es:[bx + 28]
+    mov     di,     es:[bx + 30]
+    
+    add     si,     es:[bx + 14]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 22],     si
+    mov     word ptr [bp - 24],     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     es:[bx + 16]
+    cbw
+    
+    push    ax
+    
+    mul     word ptr es:[bx + 38]
+    add     di,     ax
+    
+    pop     ax
+    mul     word ptr es:[bx + 36]
+    
+    add     ax,     si
+    adc     dx,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 8],      ax
+    mov     word ptr [bp - 10],     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector mask.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx + 11]
+    shr     ax
+    shr     ax
+    dec     ax
+    
+    mov     word ptr [bp - 12],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the sector shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+    
+    xchg    ax,     cx
+    inc     cx
+
+.L26:
+
+    inc     ax
+    shr     cx
+    
+    cmp     cx,     1
+    jne     .L26
+    
+    mov     word ptr [bp - 14],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump passed the oldfat calculations.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     .L25
+
+.L12:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     es:[bx + 28]
+    mov     di,     es:[bx + 30]
+    
+    add     si,     es:[bx + 14]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 22],     si
+    mov     word ptr [bp - 24],     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     es:[bx + 16]
+    cbw
+    mul     word ptr es:[bx + 22]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the FAT offset to get the root directory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 16],     si
+    mov     word ptr [bp - 18],     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors the root directory requires.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0020)
+    mul     word ptr es:[bx + 17]
+    div     word ptr es:[bx + 11]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the root offset to get the data offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 8],      si
+    mov     word ptr [bp - 10],     di
+
+.L25:
+
+    xor     di,     di
+    
+    mov     ax,     HEX (80)
+    xor     dx,     dx
+    
+    call    _kmalloc
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First, thing we need is a place to store the current directory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     65
+    xor     dx,     dx
+    
+    call    _kmalloc
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Start in the root of the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp - 4]
+    stosw
+    
+    mov     ax,     word ptr [bp - 6]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need a scratch buffer for the disk so allocate one.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss:[bx + 11]
+    xor     dx,     dx
+    
+    xor     ch,     ch
+    mov     cl,     ss:[bx + 13]
+    
+    mul     cx
+    mov     word ptr [bp - 20],     ax
+
+.L24:
+
+    call    _kmalloc
+    stosw
+    
+    mov     ax,     ss
+    mov     ds,     ax
+    
+    mov     si,     bx
+    add     si,     11
+    
+    mov     cx,     25
+    rep     movsb
+    
+    mov     ax,     word ptr [bp + 4]
+    stosb
+    
+    mov     ax,     word ptr [bp - 4]
+    stosw
+    
+    mov     ax,     word ptr [bp - 6]
+    stosw
+    
+    mov     ax,     word ptr [bp - 22]
+    stosw
+    
+    mov     ax,     word ptr [bp - 24]
+    stosw
+    
+    mov     ax,     word ptr [bp - 16]
+    stosw
+    
+    mov     ax,     word ptr [bp - 18]
+    stosw
+    
+    mov     ax,     word ptr [bp - 8]
+    stosw
+    
+    mov     ax,     word ptr [bp - 10]
+    stosw
+    
+    mov     ax,     word ptr [bp - 12]
+    stosw
+    
+    mov     ax,     word ptr [bp - 14]
+    stosw
+    
+    mov     ax,     word ptr [bp - 20]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get drive parameters.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (08)                                                    ; clobbers AX, BL, CX, DX, ES:DI
+    int     HEX (13)
+    jc      .L7
+    
+    and     cx,     HEX (3F)
+    mov     es:[HEX (0015)],        cx
+    
+    mov     cl,     dh
+    inc     cx
+    mov     es:[HEX (0017)],        cx
+
+.L7:
+
+    inc     byte ptr cs:[_last_drive]
+    
+    mov     ax,     es
+    jmp     .L19
+    
+.L21:
+
+    xor     ax,     ax
+
+.L19:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     cx
+    pop     dx
+    pop     di
+    pop     si
+    pop     bx
+    pop     ds
+    pop     es
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if the partiton is active.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr [bp - 2],      1
+    je     .L22
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     24
+    clc
+    
+    jmp     .L20
+
+.L22:
+
+    add     sp,     24
+    stc
+
+.L20:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _get_hard_disk_partitions
+;******************************************************************************
+global      _get_hard_disk_partitions
+_get_hard_disk_partitions:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer and make some room
+    ;; for variables within this function.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     10
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     ax,     ss
+    mov     es,     ax
+    
+    lea     di,     [bp - 10]
+    xor     al,     al
+    
+    mov     cx,     10
+    rep     stosb
+    
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up our loop variables.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     word ptr [bp - 4],      ax
+
+.L3:
+
+    cmp     word ptr [bp - 4],      4
+    jae     .L2
+    
+    mov     dx,     word ptr [bp - 4]
+    add     dx,     HEX (80)
+    
+    xor     ax,     ax
+    mov     word ptr [bp - 2],      ax
+
+.L5:
+
+    cmp     word ptr [bp - 2],      4
+    jae     .L6
+    
+    mov     ax,     word ptr [bp - 2]
+    push    ax
+    
+    mov     ax,     dx
+    push    ax
+    
+    call    _get_partition_info
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      .L15
+    
+    jnc     .L16
+    
+    mov     es,     ax
+    xor     bx,     bx
+    
+    cmp     es:[bx + 29],   dl
+    jne     .L16
+
+.L17:
+
+    push    ax
+    
+    mov     ax,     offset _vec_parts
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    jmp     .L15
+
+.L16:
+
+    push    ds
+    
+    mov     cx,     ss
+    mov     ds,     cx
+    
+    push    ax
+    
+    lea     ax,     word ptr [bp - 10]
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    pop     ds
+
+.L15:
+
+    add     word ptr [bp - 2],      1
+    jmp     .L5
+
+.L6:
+
+    add     word ptr [bp - 4],      1
+    jmp     .L3
+
+.L2:
+
+    mov     cx,     word ptr [bp - 6]
+    xor     bx,     bx
+
+.L4:
+
+    and     cx,     cx
+    jz      .L18
+    
+    mov     ax,     word ptr [bp - 10]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    push    ax
+    
+    mov     ax,     offset _vec_parts
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    add     bx,     2
+    dec     cx
+    
+    jmp     short   .L4
+
+.L18:
+
+    mov     ax,     word ptr [bp - 10]
+    
+    mov     es,     ax
+    call    _free_mem
+
+.L1:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     10
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Pop the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _read_sectors
+;******************************************************************************
+global      _read_sectors
+_read_sectors:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    si
+    push    di
+    push    es
+
+_read_sectors.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The di regsiter will be our retry counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     HEX (0005)
+
+_read_sectors.retry:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If disk extensions aren't avaiable then we need to use CHS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_edd_available],       1
+    jb      _read_sectors.chs
+
+_read_sectors.lba:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll create the LBA read on the stack.  8086 doesn't allow pushing
+    ;; values directly so we'll use si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    push    si
+    push    si
+    
+    push    dx
+    push    ax
+    push    es
+    push    bx
+    
+    mov     si,     1
+    push    si
+    
+    mov     si,     16
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The dl register needs to be set to the drive number before we alter
+    ;; the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dl,     cs:[_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need to set si to sp as the LBA read requires ds:si.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment to the stack segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ss
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (42)
+    stc
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cleanup the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If there was no carry the we successfully read the sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnc     _read_sectors.success
+
+_read_sectors.chs:
+
+    div     word ptr cs:[_sectors_per_track]
+            ; ax = LBA / SPT
+            ; dx = LBA # SPT        = sector - 1
+    
+    mov     cx,     dx
+    inc     cx
+            ; cx = sector no.
+    
+    xor     dx,     dx
+    div     word ptr cs:[_heads_per_cylinder]
+            ; ax = (LBA / SPT) / HPC = cylinder
+            ; dx = (LBA / SPT) # HPC = head
+    
+    mov     ch,     al
+            ; ch = LSB 0...7 of cylinder no.
+    ror     ah
+    ror     ah
+    or      cl,     ah
+            ; cl = MSB 8...9 of cylinder no. + sector no.
+    mov     dh,     dl
+            ; dh = head no.
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read the sector into es:bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0201)
+    mov     dl,     cs:[_drive_no]
+    stc
+    int     HEX (13)
+    jnc     _read_sectors.success
+
+_read_sectors.failure:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     dl,     cs:[_drive_no]
+    int     HEX (13)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement the loop counter and retry if greater than zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     di
+    jnz     _read_sectors.retry
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Invoke the BIOS.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (18)
+
+_read_sectors.success:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the bytes per sector to bx to get the next offset to read in to.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     bx,     cs:[_bytes_per_sector]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the ax, cx and dx registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     1
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop until cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _read_sectors.next
+
+_read_sectors.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _drive_no
+_drive_no:                      db      HEX (00)
+
+global      _last_drive
+_last_drive:                    db      HEX (00)
+
+global      _selected_disk
+_selected_disk:                 dw      HEX (0000)
+
+global      _disk_scratch
+_disk_scratch:                  dw      HEX (0000)
+
+global      _edd_available
+_edd_available:                 dw      HEX (0000)
+
+global      _clustsize
+_clustsize:                     dw      HEX (0000)
+
+global      _vec_parts
+_vec_parts:                     db      6       dup (0)
+
+global      _disk_transfer_addr
+_disk_transfer_addr:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
diff --git a/src/kernel/divide.asm b/src/kernel/divide.asm
new file mode 100644 (file)
index 0000000..0018abf
--- /dev/null
@@ -0,0 +1,275 @@
+;******************************************************************************
+; @file             divide.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _divide_handler
+;******************************************************************************
+global      _divide_handler
+_divide_handler:
+
+    push    sp
+    push    bp
+    
+    mov     bp,     sp
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're within the kernel then we'll blue screen.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_curr_psp],        0
+    jne     _divide_handler.no_clear
+
+_divide_handler.clear:
+
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (1F)
+    xor     cx,     cx
+    mov     dx,     HEX (1850)
+    int     HEX (10)
+    
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+    
+    jmp     _divide_handler.init
+
+_divide_handler.no_clear:
+
+    call    _crlf
+
+_divide_handler.init:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the data segment is the dame as the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print our first message.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     offset _divide_handler.msg
+    call    _writestr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the segment of the error.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print a colon.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ':'
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the offset of the error.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 2]
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print a newline.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _crlf
+    call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ds
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the stack segmennt segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the stack and base pointers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 2]
+    add     ax,     3 * 2                                                       ; return address, offset, segment.
+    call    _writehex
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    mov     ax,     word ptr [bp]
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print a newline.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the general purpose registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    call    _writehex
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    mov     ax,     di
+    call    _writehex
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    pop     ax
+    call    _writehex
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    pop     ax
+    call    _writehex
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value of bx off the stack and print it.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Indent with 4 spaces.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Finally, get the value of ax off the stack and print it.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    call    _writehex
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print a newline.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _crlf
+    call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're within the kernel we don't want to try quiting
+    ;; the program.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_curr_psp],        0
+    je      _divide_handler.reboot
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Let's try and exit the current process.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (4C7F)
+    int     HEX (21)
+
+_divide_handler.reboot:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call error with our ending message.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "Press any key to reboot...",   HEX (00)
+
+_divide_handler.msg:
+
+    db      "Trap to vector 0: Divide overflow at ",     HEX (00)
diff --git a/src/kernel/error.asm b/src/kernel/error.asm
new file mode 100644 (file)
index 0000000..cfe6434
--- /dev/null
@@ -0,0 +1,85 @@
+;******************************************************************************
+; @file             _error.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _error
+;******************************************************************************
+global      _error
+_error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the address of the string from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump passed printing so that we get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _error.next
+
+_error.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_error.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _error.print
+
+_error.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Wait for a keypress.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    int     HEX (16)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Stop floppy motor.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     HEX (03F2)
+    xor     al,     al
+    out     dx,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset console.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0003)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Cold reboot.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     bx,     HEX (0472)
+    mov     word ptr es:[bx],   0
+    
+    jmp     HEX (F000) : HEX (FFF0)
diff --git a/src/kernel/fat.asm b/src/kernel/fat.asm
new file mode 100644 (file)
index 0000000..7053b0c
--- /dev/null
@@ -0,0 +1,537 @@
+;******************************************************************************
+; @file             fat.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _convert_cluster12
+;******************************************************************************
+global      _convert_cluster12
+_convert_cluster12:
+
+    cmp     ax,     HEX (0FF8)
+    jb      _convert_cluster12.c3
+    
+    stc
+    ret
+
+_convert_cluster12.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster16
+;******************************************************************************
+global      _convert_cluster16
+_convert_cluster16:
+
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster16.c3
+    
+    stc
+    ret
+
+_convert_cluster16.c3:
+
+    xor     dx,     dx
+    
+    sub     ax,     2
+    sbb     dx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    mul     bx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _convert_cluster32
+;******************************************************************************
+global      _convert_cluster32
+_convert_cluster32:
+
+    cmp     dx,     HEX (0FFF)
+    jne     _convert_cluster32.c3
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _convert_cluster32.c3
+    
+    stc
+    ret
+
+_convert_cluster32.c3:
+
+    mov     cx,     dx
+    
+    sub     ax,     2
+    sbb     cx,     0
+    
+    mov     bl,     cs:[_sectors_per_cluster]
+    dec     bx
+    
+    sub     bh,     bh
+    inc     bx
+    
+    xchg    cx,     ax
+    mul     bx
+    
+    xchg    ax,     cx
+    mul     bx
+    
+    add     dx,     cx
+    
+    add     ax,     cs:[_data_start]
+    adc     dx,     cs:[_data_start + 2]
+    
+    ret
+
+;******************************************************************************
+; @function         _getfattype
+;******************************************************************************
+global      _getfattype
+_getfattype:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    xor     ax,     ax
+    xor     dx,     dx
+
+_getfattype.init:
+
+    mov     al,     cs:[_sectors_per_cluster]
+    cbw
+    mov     si,     ax
+    
+    mov     di,     cs:[_bytes_per_sector]
+    
+    xor     dx,     dx
+    xor     cx,     cx
+    
+    mov     ax,     cs:[_total_sectors16]
+    and     ax,     ax
+    jnz     _getfattype.have_secs
+    
+    mov     ax,     cs:[_total_sectors32]
+    mov     dx,     cs:[_total_sectors32 + 2]
+
+_getfattype.have_secs:
+
+    sub     ax,     cs:[_reserved_sectors]
+    sbb     dx,     0
+    
+    mov     cl,     cs:[_number_of_fats]
+
+_getfattype.sec_fat_loop:
+
+    sub     ax,     cs:[_sectors_per_fat]
+    sbb     dx,     0
+    loop    _getfattype.sec_fat_loop
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     cs:[_root_entries]
+    
+    mov     bx,     32
+    mul     bx
+    
+    add     ax,     di
+    adc     dx,     0
+    
+    sub     ax,     1
+    sbb     dx,     0
+    
+    div     di
+    mov     bx,     ax
+    
+    pop     dx
+    pop     ax
+    
+    sub     ax,     bx
+    sbb     dx,     0
+    
+    div     si
+    
+    cmp     ax,     4096
+    ja      _getfattype.fat16
+
+_getfattype.fat12:
+
+    mov     ax,     offset _convert_cluster12
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat12
+    mov     cs:[_next_cluster],         ax
+    
+    jmp     short   _getfattype.done
+
+_getfattype.fat16:
+
+    mov     ax,     offset _convert_cluster16
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat16
+    mov     cs:[_next_cluster],         ax
+
+_getfattype.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat12
+;******************************************************************************
+global      _nextcluster_fat12
+_nextcluster_fat12:
+
+    push    cx
+    push    si
+    
+    mov     si,     ax
+
+_nextcluster_fat12.secoff:
+
+    mov     ax,     3
+    mul     si
+    shr     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat12.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     cs:[_fat_start]
+    mov     dx,     cs:[_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat12.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat12.cn_exit
+
+_nextcluster_fat12.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat12.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat12.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    push    ds
+    mov     ax,     cs:[_fat_seg]
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+    jnc     _nextcluster_fat12.even_cluster
+    
+    mov     cl,     4
+    shr     ax,     cl
+
+_nextcluster_fat12.even_cluster:
+
+    and     ax,     HEX (0FFF)
+
+_nextcluster_fat12.compare:
+
+    cmp     ax,     HEX (0FF8)
+    cmc
+
+_nextcluster_fat12.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat16
+;******************************************************************************
+global      _nextcluster_fat16
+_nextcluster_fat16:
+
+    push    cx
+    push    si
+
+_nextcluster_fat16.secoff:
+
+    shl     ax
+    
+    push    cx
+    pushf
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    shl     cx
+    
+    xor     dx,     dx
+    div     cx
+    
+    push    dx
+    xchg    si,     ax
+
+_nextcluster_fat16.read_fat:
+
+    push    es
+    push    bx
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     cs:[_fat_start]
+    mov     dx,     cs:[_fat_start + 2]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat16.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat16.cn_exit
+
+_nextcluster_fat16.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat16.cn_exit:
+
+    pop     bx
+    pop     es
+
+_nextcluster_fat16.get_clust:
+
+    pop     si
+    popf
+    pop     cx
+    
+    mov     ax,     cs:[_fat_seg]
+    jnc     _nextcluster_fat16.first64
+    
+    add     ax,     HEX (1000)
+
+_nextcluster_fat16.first64:
+
+    push    ds
+    mov     ds,     ax
+    mov     ax,     [si]
+    pop     ds
+
+_nextcluster_fat16.compare:
+
+    cmp     ax,     HEX (FFF8)
+    cmc
+
+_nextcluster_fat16.done:
+
+    xor     dx,     dx
+    
+    pop     si
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function         _nextcluster_fat32
+;******************************************************************************
+global      _nextcluster_fat32
+_nextcluster_fat32:
+
+    push    es
+    push    bx
+    push    cx
+    push    di
+    
+    mov     di,     ax
+    and     di,     cs:[_fat_secmask]
+    
+    mov     cx,     cs:[_fat_secshift]
+
+_nextcluster_fat32.cn_loop:
+
+    shr     dx
+    rcr     ax
+    loop    _nextcluster_fat32.cn_loop
+    
+    shl     di
+    shl     di
+    
+    add     ax,     cs:[_fat_start]
+    adc     dx,     cs:[_fat_start + 2]
+    
+    mov     bx,     cs:[_fat_seg]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    cmp     ax,     cs:[_fat_sector]
+    jne     _nextcluster_fat32.read
+    
+    cmp     dx,     cs:[_fat_sector + 2]
+    je      _nextcluster_fat32.cn_exit
+
+_nextcluster_fat32.read:
+
+    mov     cs:[_fat_sector],       ax
+    mov     cs:[_fat_sector + 2],       dx
+    
+    mov     cx,     2
+    call    _read_sectors
+
+_nextcluster_fat32.cn_exit:
+
+    mov     ax,     es:[di]
+    mov     dx,     es:[di + 2]
+    
+    cmp     dx,     HEX (0FFF)
+    jne     _nextcluster_fat32.no_carry
+    
+    cmp     ax,     HEX (FFF8)
+    jb      _nextcluster_fat32.no_carry
+    
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    stc
+    ret
+
+_nextcluster_fat32.no_carry:
+
+    pop     di
+    pop     cx
+    pop     bx
+    pop     es
+    
+    clc
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _fat_bpb
+_fat_bpb:                       db      25      dup (0)
+
+global      _convert_cluster
+_convert_cluster:               dw      HEX (0000)
+
+global      _next_cluster
+_next_cluster:                  dw      HEX (0000)
+
+global      _fat_seg
+_fat_seg:                       dw      HEX (0000)
+
+global      _fat_secmask
+_fat_secmask:                   dw      HEX (0000)
+
+global      _fat_secshift
+_fat_secshift:                  dw      HEX (0000)
+
+global      _curr_cluster
+_curr_cluster:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _fat_sector
+_fat_sector:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _root_cluster
+_root_cluster:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _fat_start
+_fat_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _root_start
+_root_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _data_start
+_data_start:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
diff --git a/src/kernel/fat.inc b/src/kernel/fat.inc
new file mode 100644 (file)
index 0000000..e4cd3fb
--- /dev/null
@@ -0,0 +1,20 @@
+%ifndef     _FAT_INC
+%define     _FAT_INC
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Offsets into the BPB.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     _bytes_per_sector           (_fat_bpb + 0)
+%define     _sectors_per_cluster        (_fat_bpb + 2)
+%define     _reserved_sectors           (_fat_bpb + 3)
+%define     _number_of_fats             (_fat_bpb + 5)
+%define     _root_entries               (_fat_bpb + 6)
+%define     _total_sectors16            (_fat_bpb + 8)
+%define     _media_descriptor           (_fat_bpb + 10)
+%define     _sectors_per_fat            (_fat_bpb + 11)
+%define     _sectors_per_track          (_fat_bpb + 13)
+%define     _heads_per_cylinder         (_fat_bpb + 15)
+%define     _hidden_sectors             (_fat_bpb + 17)
+%define     _total_sectors32            (_fat_bpb + 21)
+
+%endif      ; _FAT_INC
diff --git a/src/kernel/file.asm b/src/kernel/file.asm
new file mode 100644 (file)
index 0000000..f728c17
--- /dev/null
@@ -0,0 +1,1131 @@
+;******************************************************************************
+; @file             file.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _read_cluster
+;******************************************************************************
+_read_cluster:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer to the stack pointer and reserve
+    ;; some space.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     36
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    push    ds
+    push    si
+    push    di
+
+_read_cluster.walk:
+
+    and     ax,     ax
+    jz      _read_cluster.check
+    
+    push    ax
+    push    dx
+    
+    mov     ax,     bx
+    mov     dx,     cx
+    
+    call    cs:[_next_cluster]
+    jnc     _read_cluster.found
+    
+    pop     dx
+    pop     ax
+    
+    jmp     _read_cluster.done
+
+_read_cluster.found:
+
+    mov     bx,     ax
+    mov     cx,     dx
+    
+    pop     dx
+    pop     ax
+    
+    dec     ax
+    jnz     _read_cluster.walk
+
+_read_cluster.check:
+
+    mov     ax,     bx
+    mov     dx,     cx
+    
+    call    cs:[_convert_cluster]
+    jnc     _read_cluster.read
+
+_read_cluster.read:
+
+    xor     ch,     ch
+    mov     cl,     es:[si + 6]
+    
+    mov     bx,     es:[si + 68]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    call    _read_sectors
+
+_read_cluster.done:
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     36
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _getc
+;******************************************************************************
+_getc:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    mov     word ptr [bp - 2],      0
+
+_getc.is_eof:
+
+    mov     ax,     es:[si + 64]
+    mov     dx,     es:[si + 66]
+    
+    mov     cx,     ax
+    
+    or      cx,     dx
+    jz      _getc.done
+
+_getc.check:
+
+    cmp     dx,     es:[si + 62]
+    ja      _getc.check2
+    
+    cmp     dx,     es:[si + 62]
+    jne     _getc.done
+    
+    cmp     ax,     es:[si + 60]
+    jbe     _getc.done
+
+_getc.check2:
+
+    mov     ax,     es:[si + 60]
+    mov     dx,     es:[si + 62]
+    
+    mov     cx,     es:[si + 50]
+    div     cx
+    
+    cmp     word ptr es:[si + 52],      0
+    je      _getc.check_offset
+    
+    mov     word ptr es:[si + 52],      0
+    jmp     short   _getc.read
+
+_getc.check_offset:
+
+    and     dx,     dx
+    jnz     _getc.loaded
+
+_getc.read:
+
+    mov     bx,     es:[si + 56]
+    mov     cx,     es:[si + 58]
+    call    _read_cluster
+
+_getc.loaded:
+
+    push    es
+    
+    mov     bx,     es:[si + 68]
+    mov     es,     bx
+    mov     bx,     dx
+    mov     al,     es:[bx]
+    
+    mov     bx,     ds
+    mov     es,     bx
+    stosb
+    
+    mov     bx,     es
+    mov     ds,     bx
+    
+    pop     es
+    inc     word ptr [bp - 2]
+    
+    add     word ptr es:[si + 60],      1
+    adc     word ptr es:[si + 62],      0
+
+_getc.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    clc
+    
+    pop     bp
+    ret
+
+_getc.error:
+
+    xor     ax,     ax
+    
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    stc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _get_file_handle
+;******************************************************************************
+_get_file_handle:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    es
+    
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs:[_vec_files + 0]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check to see if our vector is empty.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs:[_vec_files + 2]
+    
+    and     cx,     cx
+    jz      _get_file_handle.done
+
+_get_file_handle.search:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then we have a free entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _get_file_handle.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance to the next entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     bx,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Increase our counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     word ptr [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    loop    _get_file_handle.search
+
+_get_file_handle.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set ax to the index of the file plus 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp - 2]
+    add     ax,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag to indicate success.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and eturn to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+
+;******************************************************************************
+; @function         _close_file
+;******************************************************************************
+global      _close_file
+_close_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    si
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _close_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then we have a free entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    jne     _close_file.ok
+
+_close_file.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     si
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     6
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_close_file.ok:
+
+    push    es
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Our file handle info contains a pointer to a buffer at offset
+    ;; 52 so we need to free it.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[di + 68]
+    push    es
+    
+    mov     es,     ax
+    call    _free_mem
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free our entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    call    _free_mem
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the entry to zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es:[bx],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract 1 from the length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     word ptr cs:[_vec_files + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     si
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Not sure what ax should be so just clear it for now and clear the
+    ;; carray flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function         _open_file
+;******************************************************************************
+global      _open_file
+_open_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Walk the path until we hit the last '\'.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _walk_path
+    jnc     _open_file.found_dir
+
+_open_file.not_found:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     3
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.found_dir:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Mangle the file name and search for it in the file system.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _mangle_dos_name
+    jc      _open_file.name_error
+    
+    call    _search_dos_dir
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then we couldn't find the specified file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _open_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax register should contain information about the file so
+    ;; copy it into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment as the code segment and copy the value
+    ;; in the ax register into the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The info passed back to us from _search_dos_dir should contain the
+    ;; entry type at offset 8 so move that into the cl register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     es:[bx + 8]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Was the entry a file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    cl,     HEX (18)
+    jz      _open_file.got_file
+
+_open_file.name_error:
+
+    pop     bx
+    pop     di
+
+_open_file.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.got_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get an available file info entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _get_file_handle
+    jnc     _open_file.got_handle
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag and error number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     4
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_open_file.got_handle:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the ax register
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate memory for the file info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     128
+    xor     dx,     dx
+    call    _kmalloc
+    
+    mov     es,     ax
+    xor     di,     di
+    
+    mov     ax,     cs:[_curr_cluster]
+    stosw
+    
+    mov     ax,     cs:[_curr_cluster + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value in the code segment into the data segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     cs
+    mov     ds,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the si register with the address of our BPB.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _fat_bpb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the BPB to the file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store other disk info.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     cs:[_drive_no]
+    stosb
+    
+    mov     ax,     cs:[_root_cluster]
+    stosw
+    
+    mov     ax,     cs:[_root_cluster + 2]
+    stosw
+    
+    mov     ax,     cs:[_fat_start]
+    stosw
+    
+    mov     ax,     cs:[_fat_start + 2]
+    stosw
+    
+    mov     ax,     cs:[_root_start]
+    stosw
+    
+    mov     ax,     cs:[_root_start + 2]
+    stosw
+    
+    mov     ax,     cs:[_data_start]
+    stosw
+    
+    mov     ax,     cs:[_data_start + 2]
+    stosw
+    
+    mov     ax,     cs:[_fat_secmask]
+    stosw
+    
+    mov     ax,     cs:[_fat_secshift]
+    stosw
+    
+    mov     ax,     cs:[_clustsize]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value 1 as the first word to indicate that we need
+    ;; to be read
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the starting cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 0]
+    stosw
+    
+    mov     ax,     cs:[si + 2]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; File pointer starts at zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the file size.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 4]
+    stosw
+    
+    mov     ax,     cs:[si + 6]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate memory for a buffer that will be used to keep track of
+    ;; the current data read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    
+    mov     ax,     es:[si + 50]
+    xor     dx,     dx
+    call    _kmalloc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the current Program Segment Prefix.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_curr_psp]
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore ax and re-push it to the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    push    ax
+
+_open_file.check:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached the capacity of our "vector array"?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     ax,     cs:[_vec_files + 2]
+    jb      _open_file.no_push
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so add the file info to our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    push    es
+    
+    mov     bx,     offset _vec_files
+    push    bx
+    
+    call    _vec_push
+    add     sp,     4
+    
+    jmp     short   _open_file.done
+
+_open_file.no_push:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value that in the extra segment into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the address of our vector array.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs:[_vec_files + 0]
+    mov     es,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract 3 from ax to get the real index into our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     ax,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the dx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiply by two to get the offset into the vector array.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the offset into bx and set it to the value that we copied into
+    ;; the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    mov     es:[bx],    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add one to our vector length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     word ptr cs:[_vec_files + 4]
+
+_open_file.done:
+
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+;******************************************************************************
+; @function         _read_file
+;******************************************************************************
+global      _read_file
+_read_file:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the base pointer to the stack pointer and make some room to store
+    ;; some values within this function.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    es
+    push    ds
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure our total bytes read is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we're not write-only.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[si + 54],  1
+    je      _read_file.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the buffer offset (dx) into the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     dx
+
+_read_file.loop:
+
+    call    _getc
+    jc      _read_file.error
+    
+    and     ax,     ax
+    jz      _read_file.done
+    
+    inc     word ptr [bp - 2]
+    loop    _read_file.loop
+
+_read_file.done:
+
+    mov     ax,     [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_read_file.error:
+
+    mov     ax,     6
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _seek_file
+;******************************************************************************
+global      _seek_file
+_seek_file:
+
+    push    bx
+    
+    cmp     bx,     3
+    jb      _seek_file.error
+    
+    sub     bx,     3
+    jmp     _seek_file.calc
+
+_seek_file.error:
+
+    pop     bx
+    
+    mov     ax,     6
+    stc
+    
+    ret
+
+_seek_file.calc:
+
+    push    es
+    push    si
+    push    di
+    push    ax
+    push    dx
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    pop     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then the file handle is invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    jne     _seek_file.check
+    
+    pop     dx
+    pop     ax
+    pop     di
+    pop     si
+    pop     es
+    pop     bx
+    
+    mov     ax,     6
+    stc
+    
+    ret
+
+_seek_file.check:
+
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    xor     si,     si
+    
+    pop     dx
+    pop     ax
+    
+    cmp     al,     0
+    je      _seek_file.beginning
+    
+    cmp     al,     1
+    je      _seek_file.offset
+    
+    cmp     al,     2
+    je      _seek_file.end
+    
+    pop     di
+    pop     si
+    pop     es
+    pop     bx
+    
+    mov     ax,     1
+    stc
+    
+    ret
+
+_seek_file.beginning:
+
+    xor     ax,     ax
+    
+    mov     es:[si + 60],       ax
+    mov     es:[si + 62],       ax
+    
+    jmp     short   _seek_file.offset
+
+_seek_file.end:
+
+    mov     ax,     es:[si + 64]
+    mov     es:[si + 60],   ax
+    
+    mov     ax,     es:[si + 66]
+    mov     es:[si + 62],   ax
+
+_seek_file.offset:
+
+    mov     ax,     es:[si + 60]
+    add     ax,     cx
+    
+    mov     di,     es:[si + 62]
+    adc     di,     dx
+    
+    cmp     di,     0
+    jge     _seek_file.ptr_ok
+    
+    xor     ax,     ax
+    xor     di,     di
+
+_seek_file.ptr_ok:
+
+    mov     es:[si + 60],   ax
+    mov     es:[si + 62],   di
+
+_seek_file.done:
+
+    mov     word ptr es:[si + 52],      1
+    
+    mov     ax,     es:[si + 60]
+    mov     dx,     es:[si + 62]
+    clc
+    
+    pop     di
+    pop     si
+    pop     es
+    pop     bx
+    
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _vec_files
+_vec_files:                     db     6        dup (0)
diff --git a/src/kernel/find.asm b/src/kernel/find.asm
new file mode 100644 (file)
index 0000000..36a760a
--- /dev/null
@@ -0,0 +1,512 @@
+;******************************************************************************
+; @file             find.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc file for our BPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function          _compress_filename
+;******************************************************************************
+_compress_filename:
+
+    push    si
+    push    di
+    
+    push    si
+    mov     cl,     8
+
+_compress_filename.name:
+
+    lodsb
+    
+    cmp     al,     ' '
+    je      _compress_filename.check
+    
+    stosb
+    
+    dec     cl
+    jnz     _compress_filename.name
+
+_compress_filename.check:
+
+    test    bl,     HEX (20)
+    jnz     _compress_filename.check2
+    
+    pop     si
+    
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     si
+    ret
+
+_compress_filename.check2:
+
+    pop     si
+    add     si,     8
+    
+    cmp     byte ptr [si],  ' '
+    jne     _compress_filename.need_ext
+    
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     si
+    ret
+
+_compress_filename.need_ext:
+
+    mov     al,     '.'
+    stosb
+    
+    mov     cl,     3
+
+_compress_filename.ext:
+
+    lodsb
+    
+    cmp     al,     ' '
+    je      _compress_filename.ext_done
+    
+    stosb
+    loop    _compress_filename.ext
+
+_compress_filename.ext_done:
+
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     si
+    ret
+
+;******************************************************************************
+; @function          _find_next_file
+;******************************************************************************
+_find_next_file:
+
+    push    si
+    mov     dx,     si
+
+_find_next_file.dir_loop:
+
+    push    cx
+    push    di
+    
+    mov     al,     es:[bx]
+    
+    and     al,     al
+    jz      _find_next_file.advance
+    
+    cmp     al,     HEX (E5)
+    je      _find_next_file.advance
+    
+    mov     di,     bx
+    mov     si,     dx
+    mov     cx,     11
+
+_find_next_file.compare:
+
+    lodsb
+    
+    cmp     al,     '?'
+    je      _find_next_file.wild
+    
+    cmp     al,     es:[di]
+    jne     _find_next_file.advance
+
+_find_next_file.wild:
+
+    inc     di
+    loop    _find_next_file.compare
+    
+    jmp     short   _find_next_file.done
+
+_find_next_file.advance:
+
+    pop     di
+    pop     cx
+    
+    add     bx,     32
+    add     di,     32
+    
+    loop    _find_next_file.dir_loop
+
+_find_next_file.not_found:
+
+    mov     bx,     HEX (FFFF)
+    
+    pop     si
+    ret
+
+_find_next_file.done:
+
+    pop     di
+    pop     cx
+    
+    pop     si
+    ret
+
+;******************************************************************************
+; @function         _find_file
+;******************************************************************************
+global      _find_file
+_find_file:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     42
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    cmp     word ptr es:[bx + 13],      HEX (FFFF)
+    je      _find_file.error
+    
+    mov     ax,     es:[bx + 13]
+    mov     word ptr [bp - 36],     ax
+    
+    mov     word ptr [bp - 42],     es
+    mov     word ptr [bp - 32],     bx
+    
+    mov     word ptr [bp - 20],     0
+    mov     word ptr [bp - 16],     0
+    
+    mov     ax,     es:[bx + 13]
+    xor     dx,     dx
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    div     cx
+    
+    mov     word ptr [bp - 40],     ax
+    mov     word ptr [bp - 38],     dx
+    
+    mov     ax,     es:[bx + 15]
+    mov     dx,     es:[bx + 19]
+    
+    mov     bx,     ax
+    or      bx,     dx
+    
+    and     bx,     bx
+    jnz     _find_file.not_root
+    
+    mov     ax,     cs:[_root_start]
+    mov     dx,     cs:[_root_start + 2]
+
+_find_file.got_root:
+
+    mov     word ptr [bp - 30],     1
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    mov     ax,     32
+    xor     dx,     dx
+    
+    mov     cx,     cs:[_root_entries]
+    mul     cx
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    div     cx
+    
+    xchg    cx,     ax
+    dec     cx
+    
+    xor     dx,     dx
+    mov     word ptr [bp - 22],     cx
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _find_file.read
+
+_find_file.not_root:
+
+    mov     word ptr [bp - 30],     0
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    call    cs:[_convert_cluster]
+    jc      _find_file.not_found
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_sectors_per_cluster]
+    
+    mov     word ptr [bp - 34],     cx
+    dec     word ptr [bp - 34]
+
+_find_file.read:
+
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    mov     cx,     word ptr [bp - 24]
+    call    _read_sectors
+    
+    mov     ax,     cs:[_bytes_per_sector]
+    xor     dx,     dx
+    
+    mov     cx,     32
+    div     cx
+    xchg    cx,     ax
+    
+    mov     ax,     word ptr [bp - 38]
+    xor     dx,     dx
+    
+    mov     bx,     32
+    div     bx
+    
+    sub     cx,     ax
+
+_find_file.search:
+
+    mov     di,     word ptr [bp - 36]
+    
+    mov     ax,     word ptr [bp - 42]
+    mov     ds,     ax
+    
+    mov     si,     word ptr [bp - 32]
+    inc     si
+    
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    
+    mov     bx,     word ptr [bp - 38]
+    call    _find_next_file
+    
+    mov     si,     es
+    mov     ds,     si
+    mov     si,     bx
+    
+    mov     bx,     word ptr [bp - 42]
+    mov     es,     bx
+    mov     bx,     word ptr [bp - 32]
+    
+    mov     es:[bx + 13],   di
+    
+    mov     word ptr [bp - 38],     si
+    mov     word ptr [bp - 36],     di
+    
+    cmp     si,     HEX (FFFF)
+    je      _find_file.check2
+    
+    mov     al,     [si + 11]
+    
+    and     al,     es:[bx + 12]
+    jz      _find_file.found
+    
+    add     word ptr [bp - 38],     32
+    add     word ptr [bp - 36],     32
+    
+    loop    _find_file.search
+
+_find_file.check2:
+
+    cmp     word ptr [bp - 30],     1
+    jne     _find_file.check
+    
+    mov     ax,     word ptr [bp - 22]
+    
+    and     ax,     ax
+    jz      _find_file.not_found
+    
+    dec     ax
+    mov     word ptr [bp - 22],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    mov     cx,     word ptr [bp - 24]
+    mov     word ptr [bp - 38],     0
+    
+    jmp     _find_file.read
+
+_find_file.check:
+
+    mov     ax,     word ptr [bp - 34]
+    
+    and     ax,     ax
+    jz      _find_file.next_clust
+    
+    dec     ax
+    mov     word ptr [bp - 34],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    mov     cx,     word ptr [bp - 24]
+    mov     word ptr [bp - 38],     0
+    
+    jmp     _find_file.read
+
+_find_file.next_clust:
+
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    call    cs:[_next_cluster]
+    jc      _find_file.not_found
+    
+    mov     bx,     word ptr [bp - 36]
+    mov     es,     bx
+    mov     bx,     word ptr [bp - 32]
+    
+    mov     word ptr es:[bx + 13],      0
+    mov     es:[bx + 15],       ax
+    mov     es:[bx + 19],       dx
+    
+    mov     word ptr [bp - 38],     0
+    jmp     _find_file.not_root
+
+_find_file.not_found:
+
+    mov     word ptr es:[bx + 13],      HEX (FFFF)
+
+_find_file.error:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     42
+    pop     bp
+    
+    mov     ax,     3
+    stc
+    
+    ret
+
+_find_file.found:
+
+    cmp     word ptr es:[bx + 13],      HEX (FFFF)
+    je      _find_file.check_end
+    
+    add     word ptr es:[bx + 13],      32
+
+_find_file.check_end:
+
+    cmp     word ptr [bp - 30],     1
+    je      _find_file.root_end
+    
+    mov     ax,     cs:[_bytes_per_sector]
+    xor     dx,     dx
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_sectors_per_cluster]
+    
+    mul     cx
+    
+    cmp     es:[bx + 13],   ax
+    jb      _find_file.fill
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    call    cs:[_next_cluster]
+    jc      _find_file.end
+    
+    mov     word ptr es:[bx + 13],      0
+    mov     es:[bx + 15],       ax
+    mov     es:[bx + 19],       dx
+    
+    jmp     _find_file.fill
+
+_find_file.end:
+
+    mov     word ptr es:[bx + 13],      HEX (FFFF)
+    jmp     _find_file.fill
+
+_find_file.root_end:
+
+    cmp     word ptr [bp - 22],     0
+    ja      _find_file.fill
+    
+    mov     word ptr es:[bx + 13],      HEX (FFFF)
+
+_find_file.fill:
+
+    mov     ax,     [si + 22]
+    mov     es:[bx + 22],   ax
+    
+    mov     ax,     [si + 24]
+    mov     es:[bx + 24],   ax
+    
+    mov     ax,     [si + 28]
+    mov     es:[bx + 26],   ax
+    
+    mov     ax,     [si + 30]
+    mov     es:[bx + 28],   ax
+    
+    push    bx
+    
+    mov     di,     word ptr [bp - 42]
+    mov     es,     di
+    
+    mov     di,     word ptr [bp - 32]
+    add     di,     30
+    
+    mov     bl,     [si + 11]
+    call    _compress_filename
+    
+    pop     bx
+
+_find_file.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     42
+    pop     bp
+    
+    xor     ax,     ax
+    clc
+    
+    ret
diff --git a/src/kernel/int21.asm b/src/kernel/int21.asm
new file mode 100644 (file)
index 0000000..bff6bb3
--- /dev/null
@@ -0,0 +1,3282 @@
+;******************************************************************************
+; @file             int21.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _bcd2int
+;******************************************************************************
+_bcd2int:
+
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     bx,     ax
+    
+    and     ax,     HEX (0F)
+    xchg    cx,     ax
+    
+    shr     bx
+    shr     bx
+    shr     bx
+    shr     bx
+    
+    and     bx,     HEX (0F)
+    
+    mov     ax,     10
+    mul     bx
+    
+    add     cx,     ax
+    xchg    ax,     cx
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    ret
+
+;******************************************************************************
+; @function          _expand_file_spec
+;******************************************************************************
+_expand_file_spec:
+
+    push    ax
+    push    bx
+    push    si
+    push    di
+    
+    mov     si,     dx
+    add     bx,     1                                                           ; search template
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; 1. Start with 11 spaces and the cursor at position 1.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     bx
+    mov     cx,     11
+    mov     al,     ' '
+    rep     stosb
+    
+    mov     di,     bx                                                          ; cursor at position 1
+
+_expand_file_spec.read_char:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; 2. Read a character from input and stop if at end.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    and     al,     al
+    jz      _expand_file_spec.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; 3. If the next character is a dot then set extension to '   '
+    ;      move the cursor to position 9 and go to step 2.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     al,     '.'
+    jne     _expand_file_spec.check_asterisk
+    
+    mov     byte ptr es:[bx + 8],   ' '
+    mov     byte ptr es:[bx + 9],   ' '
+    mov     byte ptr es:[bx + 10],  ' '
+    
+    mov     di,     bx
+    add     di,     8
+    
+    jmp     _expand_file_spec.read_char
+
+_expand_file_spec.check_asterisk:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; 4. If the next character is an asterisk, then fill the rest of the
+    ;;    pattern with question marks and move the cursor past the end
+    ;;    and go to step 2.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     al,     '*'
+    jne     _expand_file_spec.not_asterisk
+    
+    mov     cx,     bx
+    sub     cx,     di
+    add     cx,     11
+    mov     al,     '?'
+    rep     stosb
+    
+    mov     di,     bx
+    add     di,     11
+    
+    jmp     _expand_file_spec.read_char
+
+_expand_file_spec.not_asterisk:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; 5. If not past the end, copy the character, and go to step 2.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     di
+    sub     cx,     bx
+    
+    cmp     cx,     11
+    jae     _expand_file_spec.read_char
+    
+    cmp     al,     'a'
+    jb      _expand_file_spec.store
+    
+    cmp     al,     'z'
+    ja      _expand_file_spec.store
+    
+    and     al,     HEX (DF)
+
+_expand_file_spec.store:
+
+    stosb
+    jmp     _expand_file_spec.read_char
+
+_expand_file_spec.done:
+
+    pop     di
+    pop     si
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _get_disk_info
+;******************************************************************************
+_get_disk_info:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    push    ds
+    
+    mov     ax,     cs:[_selected_disk]
+    mov     word ptr [bp - 2],      ax
+
+_get_disk_info.check:
+
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    cmp     ax,     2
+    jb      _get_disk_info.got_disk
+    
+    cmp     byte ptr [si + 1],      ':'
+    jne     _get_disk_info.got_disk
+    
+    xor     ah,     ah
+    mov     al,     [si]
+    
+    push    ax
+    
+    call    _isalpha
+    mov     cx,     ax
+    
+    pop     ax
+    
+    and     cx,     cx
+    jz      _get_disk_info.got_disk
+    
+    add     si,     2
+    push    ax
+    
+    call    _toupper
+    add     sp,     2
+    
+    sub     al,     HEX (41)
+    
+    cmp     ax,     cs:[_selected_disk]
+    je      _get_disk_info.got_disk
+    
+    mov     word ptr [bp - 2],      ax
+    inc     ax
+    
+    cmp     cs:[_vec_parts + 4],    ax
+    jb      _get_disk_info.error
+    
+    dec     ax
+    
+    cmp     ax,     2
+    jae     _get_disk_info.got_disk
+    
+    call    _probe_disk
+    jc      _get_disk_info.error
+
+_get_disk_info.got_disk:
+
+    mov     ax,     word ptr [bp - 2]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_parts]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+
+_get_disk_info.copy:
+
+    push    si
+    
+    mov     ds,     ax
+    xor     si,     si
+    
+    lodsw
+    ;mov     cs:[_curr_path],    ax
+    
+    lodsw
+    mov     cs:[_curr_cluster],     ax
+    
+    lodsw
+    mov     cs:[_curr_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_disk_scratch],     ax
+    
+    mov     di,     offset _fat_bpb
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     cx,     25
+    rep     movsb
+    
+    lodsb
+    mov     cs:[_drive_no],     al
+    
+    lodsw
+    mov     cs:[_root_cluster],     ax
+    
+    lodsw
+    mov     cs:[_root_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_fat_start],    ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_root_start],   ax
+    
+    lodsw
+    mov     cs:[_root_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_data_start],   ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],       ax
+    
+    lodsw
+    mov     cs:[_fat_secmask],      ax
+    
+    lodsw
+    mov     cs:[_fat_secshift],     ax
+    
+    lodsw
+    mov     cs:[_clustsize],    ax
+    
+    pop     si
+    
+    mov     bx,     cs:[_root_cluster]
+    mov     cx,     cs:[_root_cluster + 2]
+    
+    or      bx,     cx
+    
+    and     bx,     bx
+    jnz     _get_disk_info.fat32
+    
+    call    _getfattype
+    jmp     _get_disk_info.done
+
+_get_disk_info.fat32:
+
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],         ax
+
+_get_disk_info.done:
+
+    mov     word ptr cs:[_fat_sector],  ax
+    mov     word ptr cs:[_fat_sector + 2],  ax
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     2
+    clc
+    
+    pop     bp
+    ret
+
+_get_disk_info.error:
+
+    xor     ax,     ax
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     2
+    stc
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _probe_disk
+;******************************************************************************
+_probe_disk:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     dx,     ax
+
+_probe_disk.read:
+
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Okay, we are booted from a floppy so we need to figure out which
+    ;; address it is within our _Vec_parts "structure".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_parts]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try and read the drive.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    
+    mov     ax,     es:[HEX (0006)]
+    mov     es,     ax
+    xor     bx,     bx
+    
+    mov     ax,     HEX (0201)
+    mov     cx,     HEX (0001)
+    stc
+    int     HEX (13)
+    pop     es
+    jc      _probe_disk.error
+    
+    mov     ax,     es:[HEX (0006)]
+    mov     ds,     ax
+
+_probe_disk.check:
+
+    cmp     byte ptr [HEX (0000)],      HEX (EB)
+    jne     _probe_disk.error
+    
+    cmp     byte ptr [HEX (0002)],      HEX (90)
+    jne     _probe_disk.error
+
+_probe_disk.calc:
+
+    mov     di,     8
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Next we'll copy the BPB to our "structure".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     bx
+    add     si,     11
+    
+    mov     cx,     25
+    rep     movsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the drive number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     dl
+    stosb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Floppies should be FAT12 so pad with zeros.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    xor     dx,     dx
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     [HEX (001C)]
+    mov     di,     [HEX (001E)]
+    
+    add     si,     [HEX (000E)]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     di
+    pop     di
+    
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     cx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Repush di and reset the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    
+    push    di
+    mov     di,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     [HEX (0010)]
+    cbw
+    mul     word ptr [HEX (0016)]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the FAT offset to get the root directory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     di
+    pop     di
+    
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     cx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Repush di and reset the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    
+    push    di
+    mov     di,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors the root directory requires.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0020)
+    mul     word ptr [HEX (0011)]
+    div     word ptr [HEX (000B)]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the root offset to get the data offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     di
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     dx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Floppies shouldn't have a sector mask or shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Figure out how big a cluster is.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [HEX (000B)]
+    xor     dx,     dx
+    
+    xor     ch,     ch
+    mov     cl,     [HEX (000D)]
+    
+    mul     cx
+    stosw
+    
+    clc
+    jmp     _probe_disk.done
+
+_probe_disk.error:
+
+    stc
+
+_probe_disk.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _int21_dispatch
+;******************************************************************************
+global      _int21_dispatch
+_int21_dispatch:
+
+    mov     cs:[_user_sssp + 2],    ss
+    mov     cs:[_user_sssp],        sp
+    
+    mov     cs:[_user_ax],      ax
+    mov     cs:[_user_bp],      bp
+    
+    cmp     ah,     HEX (01)
+    jb      _int21_dispatch.no_key
+    
+    cmp     ah,     HEX (05)
+    jbe     _int21_dispatch.check
+    
+    cmp     ah,     HEX (08)
+    jb      _int21_dispatch.no_key
+    
+    cmp     ah,     HEX (0B)
+    ja      _int21_dispatch.no_key
+
+_int21_dispatch.check:
+
+    push    ax
+    mov     ah,     HEX (01)
+    int     HEX (16)
+    pop     ax
+    jz      _int21_dispatch.no_key
+    
+    push    ax
+    xor     ah,     ah
+    int     HEX (16)
+    cmp     ax,     HEX (2E03)
+    pop     ax
+    jne     _int21_dispatch.no_key
+    
+    mov     al,     '^'
+    call    _writechr
+    
+    mov     al,     'C'
+    call    _writechr
+    
+    jmp     _spawn_int23
+
+_int21_dispatch.no_key:
+
+    cld                                                                         ; Make sure direction flag is always clean
+    push    bx
+    push    bp
+    
+    ;mov     bp,     sp
+    ;mov     word ptr [bp + 2],      bx
+    
+    mov     bp,     offset _int21_dispatch.list
+    mov     bx,     offset _int21_dispatch.list_end
+
+_int21_dispatch.L:
+
+    cmp     bp,     bx
+    jae     _int21_dispatch.unimpl
+    
+    cmp     ah,     cs:[bp]
+    jne     _int21_dispatch.next
+    
+    mov     bx,     cs:[bp + 1]
+    
+    mov     bp,     sp
+    xchg    word ptr [bp + 2],  bx
+    
+    pop     bp
+    ret
+
+_int21_dispatch.next:
+
+    add     bp,     3
+    
+    cmp     bp,     bx
+    jb      _int21_dispatch.L
+
+_int21_dispatch.unimpl:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    and     dl,     dl
+    jz      _int21_dispatch.col_ok
+    
+    mov     al,     HEX (0D)
+    call    _writechr
+    
+    mov     al,     HEX (0A)
+    call    _writechr
+
+_int21_dispatch.col_ok:
+
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Unimplemented syscall.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    ds
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _int21_dispatch.err
+    call    _writestr
+    
+    pop     ds
+    pop     ax
+    push    di
+    
+    mov     word ptr cs:[_writehex_num_digits],     2
+    call    _writehex
+    mov     word ptr cs:[_writehex_num_digits],     4
+    
+    pop     di
+    call    _crlf
+    
+    pop     bp
+    pop     bx
+    iret
+
+_int21_dispatch.halt:
+
+    hlt
+    jmp     short   _int21_dispatch.halt
+
+_int21_dispatch.err:
+
+    db      "Not implemented: INT 21h/AH=",     0x00
+
+_int21_dispatch.list:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Program Terminate.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (00)
+    dw      _int21_00
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Display Output.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (02)
+    dw      _int21_02
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Direct Console Input Without Echo.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (07)
+    dw      _int21_07
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Console Input Without Echo.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (08)
+    dw      _int21_08
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print String.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (09)
+    dw      _int21_09
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Buffered Keyboard Input.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (0A)
+    dw      _int21_0A
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Select Disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (0E)
+    dw      _int21_0E
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get Current Default Drive.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (19)
+    dw      _int21_19
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set Disk Transfer Address (DTA).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (1A)
+    dw      _int21_1A
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set Interrupt Vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (25)
+    dw      _int21_25
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get Date.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (2A)
+    dw      _int21_2A
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get Time.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (2C)
+    dw      _int21_2C
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get DOS Version Number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (30)
+    dw      _int21_30
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set Current Directory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3B)
+    dw      _int21_3B
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Create File Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;db      HEX (3C)
+    ;dw      _int21_3C
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Open File Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3D)
+    dw      _int21_3D
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Close File Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3E)
+    dw      _int21_3E
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read From File or Device Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3F)
+    dw      _int21_3F
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Delete/Unlink File.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;db      HEX (41)
+    ;dw      _int21_41
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move File Pointer Using Handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (42)
+    dw      _int21_42
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get Current Directory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (47)
+    dw      _int21_47
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (48)
+    dw      _int21_48
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free Allocated Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (49)
+    dw      _int21_49
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Modify Allocated Memory Blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4A)
+    dw      _int21_4A
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Exec Program.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4B)
+    dw      _int21_4B
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Terminate Process With Return Code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4C)
+    dw      _int21_4C
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Find First Matching File.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4E)
+    dw      _int21_4E
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Find Next Matching File.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (4F)
+    dw      _int21_4F
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Create File.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;db      HEX (5B)
+    ;dw      _int21_5B
+
+_int21_dispatch.list_end:
+
+;******************************************************************************
+; @function         iretc
+;******************************************************************************
+iretc:
+
+    push    bp
+    
+    mov     bp,     sp
+    jc      iretc.c
+    
+    and     byte ptr [bp + 6],  HEX (FE)                                        ; clear carry
+    jmp     short   iretc.ret
+
+iretc.c:
+
+    or      byte ptr [bp + 6],  1                                               ; set carry
+
+iretc.ret:
+
+    pop     bp
+    iret
+
+
+;******************************************************************************
+; @function         _int21_00
+; @brief            Program Terminate
+;******************************************************************************
+_int21_00:
+
+    xor     al,     al
+    jmp     _int21_4C
+
+;******************************************************************************
+; @function         _int21_02
+; @brief            Display Ouput
+;
+; @in               DL -> Character to output.
+;******************************************************************************
+_int21_02:
+
+    push    ax
+    
+    mov     al,     dl
+    call    _writechr
+    
+    pop     ax
+    iret
+
+;******************************************************************************
+; @function         _int21_07
+; @brief            Direct Console Input Without Echo
+;******************************************************************************
+_int21_07:
+
+    mov     al,     cs:[_int21_07.got_extend]
+    
+    and     al,     al
+    jz      _int21_07.wait
+    
+    mov     byte ptr cs:[_int21_07.got_extend],      0
+    jmp     _int21_07.done
+
+_int21_07.wait:
+
+    xor     ah,     ah
+    int     HEX (16)
+    
+    and     al,     al
+    jnz     _int21_07.done
+    
+    mov     cs:[_int21_07.got_extend],       ah
+
+_int21_07.done:
+
+    mov     ah,     HEX (07)
+    iret
+
+_int21_07.got_extend:            db      HEX (00)
+
+;******************************************************************************
+; @function         _int21_08
+; @brief            Console Input Without Echo
+;******************************************************************************
+_int21_08:
+
+    mov     al,     cs:[_int21_08.scan]
+    
+    and     al,     al
+    jz      _int21_08.wait
+    
+    mov     byte ptr cs:[_int21_08.scan],    0
+    jmp     _int21_08.done
+
+_int21_08.wait:
+
+    xor     ah,     ah
+    int     HEX (16)
+    
+    cmp     ax,     HEX (2E03)
+    jne     _int21_08.char_ok
+    
+    mov     al,     '^'
+    call    _writechr
+    
+    mov     al,     'C'
+    call    _writechr
+    
+    mov     al,     HEX (0D)
+    call    _writechr
+    
+    mov     al,     HEX (0A)
+    call    _writechr
+    
+    jmp     _spawn_int23
+
+_int21_08.char_ok:
+
+    mov     cs:[_int21_08.scan],     ah
+    
+    and     al,     al
+    jz      _int21_08.done
+    
+    mov     byte ptr cs:[_int21_08.scan],    0
+
+_int21_08.done:
+
+    mov     ah,     HEX (08)
+    iret
+
+_int21_08.scan:                  db      HEX (00)
+
+;******************************************************************************
+; @function         _int21_09
+; @brief            Print String
+;
+; @in               DS:DX -> Pointer to string ending in '$'.
+;******************************************************************************
+_int21_09:
+
+    push    ax
+    push    si
+    
+    mov     si,     dx
+
+_int21_09.loop:
+
+    lodsb
+    
+    cmp     al,     '$'
+    je      _int21_09.done
+    
+    call    _writechr
+    jmp     short   _int21_09.loop
+
+_int21_09.done:
+
+    pop     si
+    pop     ax
+    iret
+
+;******************************************************************************
+; @function         _int21_0A
+; @brief            Buffered Keyboard Input
+;
+; @in               DS:DX -> Pointer to input buffer of the format:
+;                       | max | count | BUFFER (N bytes)
+;                          |      |         `------- input buffer
+;                          |      `------------ number of characters returned (byte)
+;                          `-------------- maximum number of characters to read (byte)
+;******************************************************************************
+_int21_0A:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     4
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    mov     [bp - 2],   dh
+    mov     [bp - 1],   dl
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    mov     di,     dx
+    
+    mov     cx,     [di]
+    add     di,     2
+    
+    and     cl,     cl
+    jz      _int21_0A.ret
+    
+    dec     cl
+    
+    cmp     ch,     cl
+    jae     _int21_0A.ret
+    
+    xor     bh,     bh
+    mov     bl,     ch
+    add     di,     bx
+
+_int21_0A.get_chars:
+
+    xor     ax,     ax
+    int     HEX (16)
+    
+    cmp     ax,     HEX (2E03)
+    jne     _int21_0A.check_key
+    
+    mov     al,     HEX (0D)
+    stosb
+    
+    mov     di,     dx
+    mov     byte ptr [di + 1],      0
+    
+    mov     al,     '^'
+    call    _writechr
+    
+    mov     al,     'C'
+    call    _writechr
+    
+    mov     al,     HEX (0D)
+    call    _writechr
+    
+    mov     al,     HEX (0A)
+    call    _writechr
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     4
+    pop     bp
+    
+    jmp     _spawn_int23
+
+_int21_0A.check_key:
+
+    cmp     ax,     HEX (0E7F)
+    je      _int21_0A.handle_bs
+    
+    cmp     ah,     HEX (4B)
+    je      _int21_0A.handle_bs
+    
+    cmp     al,     HEX (0D)
+    je      _int21_0A.done
+    
+    cmp     al,     HEX (08)
+    jne     _int21_0A.not_bs
+
+_int21_0A.handle_bs:
+
+    and     ch,     ch
+    jz      _int21_0A.get_chars
+    
+    xor     ah,     ah
+    mov     al,     [bp - 1]
+    
+    push    cx
+    push    dx
+    xor     dx,     dx
+    
+    mov     cl,     ch
+    xor     ch,     ch
+    add     ax,     cx
+    
+    mov     cx,     HEX (50)
+    div     cx
+    
+    xchg    ax,     dx
+    pop     dx
+    pop     cx
+    
+    and     ax,     ax
+    jnz     _int21_0A.handle_bs2
+    
+    push    ax
+    push    bx
+    push    dx
+    push    cx
+    
+    mov     ax,     HEX (0300)
+    xor     bx,     bx
+    int     HEX (10)
+    
+    pop     cx
+    dec     dh
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (50)
+    int     HEX (10)
+    
+    call    _int21_0A.erase_char
+    
+    mov     ax,     HEX (0200)
+    xor     bx,     bx
+    mov     dl,     HEX (4F)
+    int     HEX (10)
+    
+    pop     dx
+    pop     bx
+    pop     ax
+    
+    dec     ch
+    dec     di
+    mov     byte ptr es:[di],       0
+    
+    jmp     _int21_0A.get_chars
+
+_int21_0A.handle_bs2:
+
+    call    _int21_0A.erase_char
+    
+    dec     ch
+    dec     di
+    mov     byte ptr es:[di],       0
+    
+    jmp     _int21_0A.get_chars
+
+_int21_0A.not_bs:
+
+    cmp     ch,     cl
+    jae     _int21_0A.get_chars
+    
+    cmp     al,     HEX (20)
+    jb      _int21_0A.get_chars
+    
+    cmp     al,     HEX (7F)
+    ja      _int21_0A.get_chars
+    
+    call    _writechr
+    stosb
+    
+    inc     ch
+    jmp     _int21_0A.get_chars
+
+_int21_0A.done:
+
+    mov     al,     HEX (0D)
+    stosb
+    
+    mov     di,     dx
+    mov     [di + 1],   ch
+
+_int21_0A.ret:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     4
+    pop     bp
+    
+    iret
+
+_int21_0A.erase_char:
+
+    mov     al,     HEX (08)
+    call    _writechr
+    
+    mov     al,     HEX (20)
+    call    _writechr
+    
+    mov     al,     HEX (08)
+    jmp     _writechr
+
+;******************************************************************************
+; @function         _int21_OE
+; @brief            Select Disk
+;******************************************************************************
+_int21_0E:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+
+_int21_0E.check:
+
+    xor     dh,     dh
+    
+    cmp     dx,     cs:[_selected_disk]
+    je      _int21_0E.done
+    
+    inc     dx
+    
+    cmp     cs:[_vec_parts + 4],    dx
+    jb      _int21_0E.done
+    
+    dec     dx
+    
+    cmp     dx,     2
+    jae     _int21_0E.set
+    
+    mov     ax,     dx
+    
+    call    _probe_disk
+    jc      _int21_0E.done
+
+_int21_0E.set:
+
+    mov     cs:[_selected_disk],    dx
+
+_int21_0E.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    mov     al,     cs:[_last_drive]
+    
+    cmp     al,     5
+    jae     _int21_0E.ret
+    
+    mov     al,     5
+
+_int21_0E.ret:
+
+    iret
+
+;******************************************************************************
+; @function         _int21_19
+; @brief            Get Current Default Drive
+;
+; @out              AL -> Current default drive.
+;******************************************************************************
+_int21_19:
+
+    mov     al,     cs:[_selected_disk]
+    iret
+
+;******************************************************************************
+; @function         _int21_1A
+; @brief            Set Disk Transfer Address (DTA)
+;
+; @in               DS:DX -> Pointer to disk transfer address.
+;******************************************************************************
+_int21_1A:
+
+    mov     cs:[_disk_transfer_addr],       dx
+    mov     cs:[_disk_transfer_addr + 2],   ds
+    
+    iret
+
+;******************************************************************************
+; @function         _int21_25
+; @brief            Set Interrupt Vector
+;
+; @in               AL -> Interrupt number.
+; @in               DS:DX = -> Pointer to interrupt handler.
+;******************************************************************************
+_int21_25:
+
+    push    es
+    push    bx
+    
+    xor     bx,     bx
+    mov     es,     bx
+    
+    mov     bl,     al
+    shl     bx
+    shl     bx
+    
+    mov     word ptr es:[bx],   dx
+    mov     word ptr es:[bx + 2],   ds
+    
+    pop     bx
+    pop     es
+    iret
+
+;******************************************************************************
+; @function         _int21_2A
+; @brief            Get Date
+;
+; @out              AL -> Day of the week (0 = Sunday).
+; @out              CX -> Year (1980 - 2009).
+; @out              DH -> Month (1 - 12).
+; @out              DL -> Day (1 - 31)
+;******************************************************************************
+_int21_2A:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     8
+    
+    push    ax
+    push    bx
+    push    si
+    push    di
+    
+    xor     cx,     cx
+    xor     dx,     dx
+    
+    mov     ah,     HEX (04)
+    clc
+    int     HEX (1A)
+    jnc     _int21_2A.ok
+    
+    mov     word ptr [bp - 8],      1980
+    mov     byte ptr [bp - 4],      1
+    mov     byte ptr [bp - 2],      1
+    
+    jmp     _int21_2A.done
+
+_int21_2A.ok:
+
+    mov     bx,     dx
+    xor     dx,     dx
+    
+    xor     ah,     ah
+    mov     al,     ch
+    call    _bcd2int
+    
+    mov     di,     100
+    mul     di
+    xchg    di,     ax
+    
+    xor     ah,     ah
+    mov     al,     cl
+    call    _bcd2int
+    
+    add     di,     ax
+    
+    cmp     di,     1980
+    jae     _int21_2A.got_year
+    
+    mov     ax,     1980
+    add     di,     ax
+
+_int21_2A.got_year:
+
+    mov     word ptr [bp - 8],  di
+    
+    xor     ah,     ah
+    mov     al,     bh
+    call    _bcd2int
+    
+    or      al,     al
+    jnz     _int21_2A.got_month
+    
+    mov     al,     1
+
+_int21_2A.got_month:
+
+    mov     byte ptr [bp - 4],  al
+    
+    xor     ah,     ah
+    mov     al,     bl
+    call    _bcd2int
+    
+    or      al,     al
+    jnz     _int21_2A.got_day
+    
+    mov     al,     1
+
+_int21_2A.got_day:
+    
+    mov     byte ptr [bp - 2],  al
+
+_int21_2A.done:
+
+    pop     di
+    pop     si
+    pop     bx
+    pop     ax
+    
+    mov     cx,     word ptr [bp - 8]
+    mov     dh,     byte ptr [bp - 4]
+    mov     dl,     byte ptr [bp - 2]
+    
+    add     sp,     8
+    pop     bp
+    
+    iret
+
+;******************************************************************************
+; @function         _int21_2C
+; @brief            Get Time
+;
+; @out              CH -> Hour (0 - 23).
+; @out              CL -> Minutes (0 - 59).
+; @out              DH -> Seconds (0 - 59).
+; @out              DL -> Hundreths (0 - 99)
+;******************************************************************************
+_int21_2C:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     6
+    
+    push    ax
+    push    bx
+    push    si
+    push    di
+    
+    xor     cx,     cx
+    xor     dx,     dx
+    
+    xor     ah,     ah
+    int     HEX (1A)
+    
+    mov     ax,     dx                                                          ; low 16 bits
+    mov     dx,     cx                                                          ; high 16 bits
+    
+    push    ax
+    push    dx
+    
+    xor     di,     di
+    push    di
+    
+    mov     di,     1
+    push    di
+    
+    mov     di,     7
+    push    di
+    
+    push    dx
+    push    ax
+    
+    call    _udivmodsi4
+    add     sp,     10
+    
+    mov     byte ptr [bp - 6],  al
+    
+    pop     dx
+    pop     ax
+    
+    mov     di,     1
+    push    di
+    
+    mov     di,     1
+    push    di
+    
+    mov     di,     7
+    push    di
+    
+    push    dx
+    push    ax
+    
+    call    _udivmodsi4
+    add     sp,     10
+    
+    mov     cx,     1092
+    div     cx
+    
+    mov     byte ptr [bp - 4],  al
+    
+    mov     ax,     100
+    mul     dx
+    
+    mov     cx,     1821
+    div     cx
+    
+    mov     byte ptr [bp - 2],  al
+
+_int21_2C.done:
+
+    pop     di
+    pop     si
+    pop     bx
+    pop     ax
+    
+    mov     ch,     byte ptr [bp - 6]
+    mov     cl,     byte ptr [bp - 4]
+    mov     dh,     byte ptr [bp - 2]
+    xor     dl,     dl
+    
+    add     sp,     6
+    pop     bp
+    
+    iret
+
+;******************************************************************************
+; @function         _int21_30
+; @brief            Get DOS Version Number
+;******************************************************************************
+_int21_30:
+
+    ;mov     ax,     HEX (0030)
+    xor     ax,     ax
+    
+    xor     bx,     bx
+    xor     cx,     cx
+    
+    iret
+
+;******************************************************************************
+; @function         _int21_3B
+; @brief            Set Current Directory
+;
+; @in               DS:DX -> ASCIIZ path name (max 64 bytes).
+;******************************************************************************
+_int21_3B:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     ax,     cs:[_selected_disk]
+    mov     word ptr [bp - 2],      ax
+    
+    mov     si,     dx
+
+_int21_3B.check3:
+
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    cmp     ax,     2
+    jb      _int21_3B.got_disk
+    
+    cmp     byte ptr [si + 1],      ':'
+    jne     _int21_3B.got_disk
+    
+    xor     ah,     ah
+    mov     al,     [si]
+    
+    push    ax
+    
+    call    _isalpha
+    mov     cx,     ax
+    
+    pop     ax
+    
+    and     cx,     cx
+    jz      _int21_3B.got_disk
+    
+    add     si,     2
+    push    ax
+    
+    call    _toupper
+    add     sp,     2
+    
+    sub     al,     HEX (41)
+    
+    cmp     ax,     cs:[_selected_disk]
+    je      _int21_3B.got_disk
+    
+    mov     word ptr [bp - 2],      ax
+    inc     ax
+    
+    cmp     cs:[_vec_parts + 4],    cx
+    jb      _int21_3B.error
+    
+    dec     ax
+    
+    cmp     ax,     2
+    jae     _int21_3B.got_disk
+    
+    call    _probe_disk
+    jc      _int21_3B.error
+
+_int21_3B.got_disk:
+
+    mov     ax,     word ptr [bp - 2]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_parts]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+
+_int21_3B.copy:
+
+    push    es
+    push    si
+    push    ds
+    
+    xor     si,     si
+    mov     ds,     ax
+    
+    lodsw
+    ;mov     cs:[_curr_path],    ax
+    
+    lodsw
+    mov     cs:[_curr_cluster],     ax
+    
+    lodsw
+    mov     cs:[_curr_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_disk_scratch],     ax
+    
+    mov     di,     offset _fat_bpb
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     cx,     25
+    rep     movsb
+    
+    lodsb
+    mov     cs:[_drive_no],     al
+    
+    lodsw
+    mov     cs:[_root_cluster],     ax
+    
+    lodsw
+    mov     cs:[_root_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_fat_start],    ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_root_start],   ax
+    
+    lodsw
+    mov     cs:[_root_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_data_start],   ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],       ax
+    
+    lodsw
+    mov     cs:[_fat_secmask],      ax
+    
+    lodsw
+    mov     cs:[_fat_secshift],     ax
+    
+    lodsw
+    mov     cs:[_clustsize],    ax
+    
+    pop     ds
+    pop     si
+    pop     es
+    
+    mov     bx,     cs:[_root_cluster]
+    mov     cx,     cs:[_root_cluster + 2]
+    
+    or      bx,     cx
+    
+    and     bx,     bx
+    jnz     _int21_3B.fat32
+    
+    call    _getfattype
+    jmp     _int21_3B.get_path
+
+_int21_3B.fat32:
+
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],         ax
+
+_int21_3B.get_path:
+
+    mov     di,     si
+    
+    push    es
+    push    di
+    
+    xor     bx,     bx
+    mov     bx,     es:[bx]
+    
+    mov     di,     offset _int21_3B.path
+    
+    mov     ax,     cs
+    mov     es,     ax
+    
+    cmp     byte ptr [si],      '\\'
+    je      _int21_3B.setup
+    
+    mov     al,     '\\'
+    stosb
+    
+    push    si
+    push    ds
+    
+    mov     ds,     bx
+    xor     si,     si
+    
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    pop     ds
+    pop     si
+
+_int21_3B.setup:
+
+    mov     ax,     offset _int21_3B.path
+    
+    mov     cx,     di
+    sub     cx,     ax
+    
+    cmp     cx,     1
+    je     _int21_3B.no_slash
+    
+    mov     al,     '\\'
+    stosb
+
+_int21_3B.no_slash:
+
+    mov     bx,     si
+
+_int21_3B.loop:
+
+    mov     ax,     si
+    sub     ax,     bx
+    
+    cmp     ax,     65
+    ja      _int21_3B.check
+    
+    lodsb
+    
+    or      al,     al
+    jz      _int21_3B.check
+    
+    cmp     al,     '.'
+    je      _int21_3B.check_curr
+    
+    cmp     al,     '\\'
+    jne     _int21_3B.convert_alpha
+    
+    cmp     si,     bx
+    je      _int21_3B.loop
+    
+    cmp     byte ptr es:[di - 1],       '\\'
+    je      _int21_3B.loop
+
+_int21_3B.convert_alpha:
+
+    xor     ah,     ah
+    push    ax
+    
+    call    _isalpha
+    
+    and     ax,     ax
+    jz      _int21_3B.no_alpha
+    
+    call    _toupper
+    add     sp,     2
+    
+    jmp     _int21_3B.char_ok
+
+_int21_3B.no_alpha:
+
+    pop     ax
+    jmp     _int21_3B.char_ok
+
+_int21_3B.check_curr:
+
+    cmp     byte ptr [si],  0
+    je      _int21_3B.loop
+    
+    cmp     byte ptr [si],  '\\'
+    je      _int21_3B.loop
+    
+    cmp     byte ptr [si],  '.'
+    je      _int21_3B.check_prev
+    
+    jmp     _int21_3B.char_ok
+
+_int21_3B.check_prev:
+
+    cmp     byte ptr [si + 1],  0
+    je      _int21_3B.get_prev
+    
+    cmp     byte ptr [si + 1],  '\\'
+    jne     _int21_3B.char_ok
+
+_int21_3B.get_prev:
+
+    mov     byte ptr es:[di - 1],   0
+    
+    push    si
+    push    ds
+    
+    mov     ax,     es
+    mov     ds,     ax
+    
+    mov     ax,     '\\'
+    push    ax
+    
+    mov     ax,     offset _int21_3B.path
+    push    ax
+    
+    call    _strrchr
+    add     sp,     4
+    
+    pop     ds
+    pop     si
+    
+    mov     di,     ax
+    inc     di
+    mov     byte ptr es:[di],   0
+    
+    jmp     _int21_3B.loop
+
+_int21_3B.char_ok:
+
+    stosb
+    jmp     _int21_3B.loop
+
+_int21_3B.check:
+
+    cmp     byte ptr es:[di - 1],       '\\'
+    jne     _int21_3B.check2
+    
+    dec     di
+
+_int21_3B.check2:
+
+    xor     al,     al
+    stosb
+    
+    pop     di
+    pop     es
+    
+    cmp     byte ptr [si],      0
+    jne     _int21_3B.error
+
+_int21_3B.search:
+
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     di,     offset _int21_3B.path
+    
+    cmp     byte ptr [di],  0
+    jne     _int21_3B.walk
+    
+    mov     ax,     cs:[_root_cluster]
+    mov     dx,     cs:[_root_cluster + 2]
+    
+    mov     es:[HEX (0002)],    ax
+    mov     es:[HEX (0004)],    dx
+    
+    xor     di,     di
+    
+    mov     ax,     es:[di]
+    mov     es,     ax
+    
+    xor     al,     al
+    
+    mov     cx,     65
+    rep     stosb
+    
+    jmp     _int21_3B.done
+
+_int21_3B.walk:
+
+    call    _walk_path
+    jc      _int21_3B.error
+    
+    call    _mangle_dos_name
+    jc      _int21_3B.error
+    
+    call    _search_dos_dir
+    jc      _int21_3B.error
+    
+    push    bx
+    push    es
+    
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    mov     ax,     es:[bx + 0]
+    mov     dx,     es:[bx + 2]
+    
+    mov     cl,     es:[bx + 8]
+    
+    pop     es
+    pop     bx
+    
+    test    cl,     HEX (10)
+    jz      _int21_3B.error
+    
+    mov     es:[HEX (0002)],    ax
+    mov     es:[HEX (0004)],    dx
+
+_int21_3B.copy2:
+
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     si,     offset _int21_3B.path
+    inc     si
+    
+    xor     di,     di
+    
+    mov     ax,     es:[di]
+    mov     es,     ax
+    
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    xor     ax,     ax
+    stosb
+    
+    jmp     _int21_3B.done
+
+_int21_3B.error:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    pop     bp
+    
+    mov     ax,     3
+    stc
+    
+    jmp     iretc
+
+_int21_3B.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    pop     bp
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     iretc
+
+_int21_3B.path:                 db      66      dup (0)
+
+;******************************************************************************
+; @function         _int21_3D
+; @brief            Open File Using Handle
+;
+; @in               AL -> Open access mode.
+; @in               DS:DX -> Pointer to an ASCIIZ file name.
+;
+; @out              AX -> File handle.  Error code if CF is set.
+;******************************************************************************
+_int21_3D:
+
+    push    bp
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    xor     bh,     bh
+    mov     bl,     al
+    
+    mov     si,     dx
+    
+    call    _get_disk_info
+    jc      _int21_3D.error
+    
+    mov     di,     si
+
+_int21_3D.open:
+
+    call    _open_file
+    jmp     _int21_3D.done
+
+_int21_3D.error:
+
+    mov     ax,     3
+    stc
+
+_int21_3D.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_3E
+; @brief            Close File Using Handle
+;
+; @in               BX -> File handle to close..
+; @out              AX -> Clear.  Error code if CF is set.
+;******************************************************************************
+_int21_3E:
+
+    call    _close_file
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_3F
+; @brief            Read From File or Device Using Handle
+;
+; @in               BX -> File handle..
+; @in               CX -> Number of bytes to read.
+; @in               DS:DX -> Pointer to read buffer.
+;
+; @out              AX -> Number of bytes read.  Error code if CF is set.
+;******************************************************************************
+_int21_3F:
+
+    push    bp
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _int21_3F.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _int21_3F.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    cx
+    
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    pop     cx
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then the file handle is invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _int21_3F.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-initialize the extra segment but this time with the address
+    ;; of the vector entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+
+_int21_3F.copy:
+
+    push    si
+    push    ds
+    push    ax
+    
+    mov     ds,     ax
+    xor     si,     si
+    
+    lodsw
+    mov     cs:[_curr_cluster],     ax
+    
+    lodsw
+    mov     cs:[_curr_cluster + 2],     ax
+    
+    mov     di,     offset _fat_bpb
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     cx,     25
+    rep     movsb
+    
+    lodsb
+    mov     cs:[_drive_no],     al
+    
+    lodsw
+    mov     cs:[_root_cluster],     ax
+    
+    lodsw
+    mov     cs:[_root_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_fat_start],    ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_root_start],   ax
+    
+    lodsw
+    mov     cs:[_root_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_data_start],   ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_fat_secmask],      ax
+    
+    lodsw
+    mov     cs:[_fat_secshift],     ax
+    
+    lodsw
+    mov     cs:[_clustsize],    ax
+    
+    mov     bx,     cs:[_root_cluster]
+    mov     cx,     cs:[_root_cluster + 2]
+    
+    or      bx,     cx
+    
+    and     bx,     bx
+    jnz     _int21_3F.fat32
+    
+    call    _getfattype
+    jmp     _int21_3F.read
+
+_int21_3F.fat32:
+
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],         ax
+
+_int21_3F.read:
+
+    pop     ax
+    pop     ds
+    pop     si
+    mov     es,     ax
+    
+    xor     si,     si
+    call    _read_file
+    
+    jmp     _int21_3F.done
+
+_int21_3F.error:
+
+    mov     ax,     6
+    stc
+
+_int21_3F.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_42
+; @brief            Move File Pointer Using Handle
+;
+; @in               AL -> Origin of move:
+;                           00 = Beginning of file plus offset (SEEK_SET)
+;                           01 = Current location plus offset (SEEK_CUR)
+;                           02 = End of file plus offset (SEEK_END)
+; @in               BX -> File handle.
+; @in               CX -> High order word of number of bytes to move.
+; @in               DX -> Low order word of number of bytes to move.
+;
+; @out              AX -> Error code if CF is set.
+; @out              DX:AX -> New pointer location if CF not set.
+;******************************************************************************
+_int21_42:
+
+    call    _seek_file
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_47
+; @brief            Get Current Directory
+;
+; @in               DL -> Drive number.
+; @in               DS:SI -> Pointer to a 64 byte user buffer.
+;
+; @out              AX -> Error code if CF is set.
+;******************************************************************************
+_int21_47:
+
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    xor     dh,     dh
+    mov     ax,     dx
+    
+    and     ax,     ax
+    jnz     _int21_47.check
+    
+    mov     ax,     cs:[_selected_disk]
+    jmp     _int21_47.got_disk
+
+_int21_47.check:
+
+    mov     cx,     cs:[_vec_parts + 4]
+    inc     ax
+    
+    cmp     ax,     cx
+    ja      _int21_47.error
+    
+    dec     ax
+
+_int21_47.got_disk:
+
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     di,     ax
+    
+    mov     ax,     cs:[_vec_parts + 0]
+    mov     es,     ax
+    
+    mov     di,     es:[di]
+    mov     es,     di
+    
+    mov     bx,     es:[HEX (0000)]
+    
+    mov     ax,     ds
+    mov     es,     ax
+    
+    mov     ds,     bx
+    
+    mov     di,     si
+    xor     si,     si
+    
+    mov     cx,     64
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    mov     ax,     HEX (0100)
+    clc
+    
+    jmp     short   _int21_47.done
+
+_int21_47.error:
+
+    mov     ax,     15
+    stc
+
+_int21_47.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_48
+; @brief            Allocate Memory Blocks
+;
+; @in               BX -> Number of memory paragraphs requested.
+;
+; @out              AX -> Segment address of allocated memory block
+;                         (MCB + lpara).  Error code if CF is set.
+; @out              BX -> Size in paras of the largets block of memory
+;                         available if CF is set and AX = 08 (Not enough mem).
+;******************************************************************************
+_int21_48:
+
+    call    _alloc_mem
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_49
+; @brief            Free Allocated Memeory Blocks
+;
+; @in               ES -> Segment of the block to be returned (MCB + lpara).
+; @out              AX -> Clear.
+;******************************************************************************
+_int21_49:
+
+    call    _free_mem
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_4A
+; @brief            Resize Allocated Memory Blocks
+;
+; @in               BX -> New requested block size in paragraphs.
+; @in               ES -> Segment of block to resize.
+;
+; @out              AX -> Segment address of memory block (MCB + lpara).
+;                         Error code if CF is set.
+; @out              BX -> Set to maximum block size possible if the request
+;                         block size is greater than what available.
+;******************************************************************************
+_int21_4A:
+
+    call    _resize_mem
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_4B
+; @brief            Exec Program
+;
+; @in               DS:DX -> Pointer to an ASCIIZ filename.
+; @in               ES:BX -> Pointer to a parameter block.
+;******************************************************************************
+_int21_4B:
+
+    and     al,     al
+    jz      _int21_4B.arg_ok
+    
+    mov     ax,     1
+    stc
+    
+    jmp     iretc
+
+_int21_4B.arg_ok:
+
+    push    bp
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    push    ax
+    push    bx
+    push    es
+    
+    mov     si,     dx
+    
+    call    _get_disk_info
+    jc      _int21_4B.disk_error
+    
+    mov     di,     si
+    
+    mov     ax,     es:[bx + 2]
+    push    ax
+    
+    mov     ax,     es:[bx + 4]
+    push    ax
+
+_int21_4B.load:
+
+    call    _load_program
+    pop     ds
+    pop     si
+    jc      _int21_4B.load_error
+    
+    and     ax,     ax
+    jnz     _int21_4B.load_ok
+
+_int21_4B.load_error:
+
+    pop     es
+    pop     bx
+    pop     si
+    
+    jmp     _int21_4B.error
+
+_int21_4B.disk_error:
+
+    pop     es
+    pop     bx
+    pop     si
+    
+    mov     ax,     3
+
+_int21_4B.error:
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    stc
+    jmp     iretc
+
+_int21_4B.load_ok:
+
+    mov     es,     ax
+    
+    mov     di,     HEX (80)
+    mov     cl,     [si]
+    mov     ch,     HEX (7E)
+    
+    cmp     cl,     ch
+    jbe     _int21_4B.copy_cmd_line
+    
+    mov     cl,     ch
+
+_int21_4B.copy_cmd_line:
+
+    xor     ch,     ch
+    inc     cl
+    rep     movsb
+    
+    mov     byte ptr es:[di],   HEX (0D)
+    pop     es
+    pop     di
+    pop     bx
+    
+    and     bl,     bl
+    jz      _int21_4B.start
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    add     di,     14
+    
+    mov     ax,     cs:[_child_sssp]
+    stosw
+    
+    mov     ax,     cs:[_child_sssp + 2]
+    stosw
+    
+    mov     ax,     cs:[_child_csip]
+    stosw
+    
+    mov     ax,     cs:[_child_csip + 2]
+    stosw
+    
+    jmp     short   _int21_4B.ret_ok
+
+_int21_4B.start:
+
+    call    _start_program
+    
+    mov     al,     cs:[_last_ret_val]
+
+_int21_4B.ret_ok:
+
+    clc
+
+_int21_4B.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    jmp     iretc
+
+;******************************************************************************
+; @function         _int21_4C
+; @brief            Terminate Process With Return Code
+;******************************************************************************
+_int21_4C:
+
+    xor     ah,     ah
+    
+    mov     cs:[_last_ret_val],     ax
+    mov     dx,     cs:[_curr_psp]
+    
+    mov     bx,     cs:[_vec_files]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     cx,     cs:[_vec_files + 2]
+    push    ds
+    push    ax
+
+_int21_4C.check_file:
+
+    and     cx,     cx
+    jz      _int21_4C.free_mem
+    
+    cmp     word ptr es:[bx],       0
+    je      _int21_4C.next_file
+    
+    mov     di,     es:[bx]
+    mov     ds,     di
+    xor     di,     di
+    
+    mov     ax,     [di + 70]
+    
+    cmp     ax,     dx
+    jne     _int21_4C.next_file
+    
+    mov     ax,     [di + 68]
+    push    es
+    
+    mov     es,     ax
+    call    _free_mem
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free our entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ds
+    mov     es,     ax
+    
+    call    _free_mem
+    pop     es
+    
+    xor     ax,     ax
+    mov     es:[bx],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Subtract 1 from the length.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     word ptr cs:[_vec_files + 4]
+
+_int21_4C.next_file:
+
+    add     bx,     2
+    dec     cx
+    
+    jmp     _int21_4C.check_file
+
+_int21_4C.free_mem:
+
+    mov     bx,     cs:[_free_seg]
+
+_int21_4C.mem_check:
+
+    mov     es,     bx
+    xor     di,     di
+    
+    cmp     bx,     cs:[_max_seg]
+    jae     _int21_4C.done
+    
+    cmp     byte ptr es:[di + 0],   'M'
+    jne     _int21_4C.next_mem
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _int21_4C.next_mem
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _int21_4C.next_mem
+    
+    mov     cx,     es:[di + 3]
+    mov     ax,     es:[di + 5]
+    
+    cmp     ax,     dx
+    jne     _int21_4C.no_free
+    
+    mov     di,     es
+    inc     di
+    
+    mov     es,     di
+    call    _free_mem
+
+_int21_4C.no_free:
+
+    add     bx,     cx
+
+_int21_4C.next_mem:
+
+    inc     bx
+    jmp     _int21_4C.mem_check
+
+_int21_4C.done:
+
+    mov     ds,     dx
+    
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     ax,     [HEX (0A)]
+    mov     es:[HEX (22) * 4],      ax
+    
+    mov     ax,     [HEX (0C)]
+    mov     es:[(HEX (22) * 4) + 2],    ax
+    
+    mov     ax,     [HEX (0E)]
+    mov     es:[HEX (23) * 4],      ax
+    
+    mov     ax,     [HEX (10)]
+    mov     es:[(HEX (23) * 4) + 2],    ax
+    
+    pop     ax
+    pop     ds
+    mov     es,     dx
+    
+    mov     sp,     es:[HEX (42)]
+    mov     ss,     es:[HEX (44)]
+    
+    mov     bx,     es:[HEX (16)]
+    mov     cs:[_curr_psp],     bx
+    
+    call    _free_mem
+    
+    xor     bx,     bx
+    mov     es,     bx
+    
+    mov     bx,     HEX (22) * 4
+    jmp     far ptr es:[bx]
+
+;******************************************************************************
+; @function         _int21_4E
+; @brief            Find First Matching File
+;
+; @in               CX -> Attribute used during search.
+; @in               DS:DX -> Pointer to ASCIIZ filespace, including wildcards.
+;******************************************************************************
+_int21_4E:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     10
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     ax,     cs:[_selected_disk]
+    mov     word ptr [bp - 10],     ax
+    
+    mov     si,     dx
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    cmp     ax,     2
+    jb      _int21_4E.got_disk
+    
+    cmp     byte ptr [si + 1],      ':'
+    jne     _int21_4E.got_disk
+    
+    xor     ah,     ah
+    mov     al,     [si]
+    
+    push    ax
+    
+    call    _isalpha
+    mov     bx,     ax
+    
+    pop     ax
+    
+    and     bx,     bx
+    jz      _int21_4E.got_disk
+    
+    push    ax
+    
+    call    _toupper
+    add     sp,     2
+    
+    sub     al,     HEX (41)
+    mov     word ptr [bp - 10],     ax
+
+_int21_4E.got_disk:
+
+    call    _get_disk_info
+    jc      _int21_4E.no_path
+    
+    mov     di,     si
+    
+    call    _walk_path
+    jc      _int21_4E.no_path
+
+_int21_4E.got_path:
+
+    mov     word ptr [bp - 6],      si
+    mov     word ptr [bp - 4],      ax
+    mov     word ptr [bp - 2],      dx
+    
+    cmp     byte ptr [si],      0
+    je      _int21_4E.get_wild
+    
+    mov     bx,     si
+
+_int21_4E.loop:
+
+    mov     al,     [bx]
+    
+    and     al,     al
+    jz      _int21_4E.search
+    
+    cmp     al,     '*'
+    je      _int21_4E.ok
+    
+    inc     bx
+    jmp     _int21_4E.loop
+
+_int21_4E.search:
+
+    mov     ax,     word ptr [bp - 4]
+    mov     dx,     word ptr [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    di
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Mangle the file name and search for it in the file system.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _mangle_dos_name
+    jc      _int21_4E.name_error
+    
+    call    _search_dos_dir
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bx
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag is set then we couldn't find the specified file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _int21_4E.no_file
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax register should contain information about the file so
+    ;; copy it into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment as the code segment and copy the value
+    ;; in the ax register into the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The info passed back to us from _search_dos_dir should contain the
+    ;; entry type at offset 8 so move that into the cl register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     es:[bx + 8]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the cluster as well.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx + 0]
+    mov     dx,     es:[bx + 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Was the entry a file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    cl,     HEX (10)
+    jz      _int21_4E.search_file
+    
+    mov     word ptr [bp - 4],      ax
+    mov     word ptr [bp - 2],      dx
+    
+_int21_4E.get_wild:
+
+    mov     si,     cs
+    mov     ds,     si
+    
+    mov     si,     offset _int21_4E.wild
+    jmp     _int21_4E.ok
+
+_int21_4E.search_file:
+
+    mov     si,     word ptr [bp - 6]
+
+_int21_4E.ok:
+
+    mov     bx,     cs:[_disk_transfer_addr + 2]
+    mov     es,     bx
+    mov     bx,     cs:[_disk_transfer_addr]
+    
+    mov     ax,     word ptr [bp - 10]
+    mov     es:[bx],    al
+    
+    mov     cx,     word ptr [bp - 8]
+    mov     ax,     word ptr [bp - 4]
+    mov     dx,     word ptr [bp - 2]
+    
+    or      cl,     HEX (31)                                                    ; bit 0 and 5 (R/O and archive) are ignored
+    not     cl
+    mov     es:[bx + 12],   cl                                                  ; Search attribute mask
+    
+    push    ax
+    push    dx
+    
+    mov     dx,     si
+    call    _expand_file_spec
+    
+    pop     dx
+    pop     ax
+    
+    mov     word ptr es:[bx + 13],  0
+    mov     es:[bx + 15],   ax
+    mov     es:[bx + 19],   dx
+    
+    call    _find_file
+    jc      _int21_4E.no_file
+
+_int21_4E.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     10
+    pop     bp
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     iretc
+
+_int21_4E.no_path:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     10
+    pop     bp
+    
+    mov     ax,     3
+    stc
+    
+    jmp     iretc
+
+_int21_4E.name_error:
+
+    pop     bx
+    pop     di
+
+_int21_4E.no_file:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     10
+    pop     bp
+    
+    mov     ax,     2
+    stc
+    
+    jmp     iretc
+
+_int21_4E.wild:                 db      "*.*",      HEX (00)
+
+;******************************************************************************
+; @function         _int21_4F
+; @brief            Find Next Matching File
+;
+; @in               DS:DX -> Unchanged from previous function 4E.
+; @out              AX -> Error code if CF is set.
+;******************************************************************************
+_int21_4F:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     8
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     bx,     cs:[_disk_transfer_addr + 2]
+    mov     es,     bx
+    mov     bx,     cs:[_disk_transfer_addr]
+    
+    xor     ah,     ah
+    mov     al,     es:[bx]
+    
+    mov     word ptr [bp - 2],      ax
+
+_int21_4F.got_disk:
+
+    inc     ax
+    
+    cmp     cs:[_vec_parts + 4],    ax
+    jb      _int21_4F.error
+    
+    dec     ax
+    
+    push    bx
+    push    es
+    push    dx
+    
+    mov     ax,     word ptr [bp - 2]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_parts]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    
+    pop     dx
+    pop     es
+    pop     bx
+
+_int21_4F.copy:
+
+    push    cx
+    push    bx
+    push    es
+    push    ds
+    push    si
+    push    di
+    
+    mov     ds,     ax
+    xor     si,     si
+    
+    lodsw
+    ;mov     cs:[_curr_path],    ax
+    
+    lodsw
+    mov     cs:[_curr_cluster],     ax
+    
+    lodsw
+    mov     cs:[_curr_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_disk_scratch],     ax
+    
+    mov     di,     offset _fat_bpb
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     cx,     25
+    rep     movsb
+    
+    lodsb
+    mov     cs:[_drive_no],     al
+    
+    lodsw
+    mov     cs:[_root_cluster],     ax
+    
+    lodsw
+    mov     cs:[_root_cluster + 2],     ax
+    
+    lodsw
+    mov     cs:[_fat_start],    ax
+    
+    lodsw
+    mov     cs:[_fat_start + 2],    ax
+    
+    lodsw
+    mov     cs:[_root_start],   ax
+    
+    lodsw
+    mov     cs:[_root_start + 2],   ax
+    
+    lodsw
+    mov     cs:[_data_start],   ax
+    
+    lodsw
+    mov     cs:[_data_start + 2],       ax
+    
+    lodsw
+    mov     cs:[_fat_secmask],      ax
+    
+    lodsw
+    mov     cs:[_fat_secshift],     ax
+    
+    lodsw
+    mov     cs:[_clustsize],    ax
+    
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    
+    mov     bx,     cs:[_root_cluster]
+    mov     cx,     cs:[_root_cluster + 2]
+    
+    or      bx,     cx
+    
+    and     bx,     bx
+    jnz     _int21_4F.fat32
+    
+    call    _getfattype
+    jmp     _int21_4F.find
+
+_int21_4F.fat32:
+
+    mov     ax,     offset _convert_cluster32
+    mov     cs:[_convert_cluster],      ax
+    
+    mov     ax,     offset _nextcluster_fat32
+    mov     cs:[_next_cluster],         ax
+
+_int21_4F.find:
+
+    pop     bx
+    pop     cx
+    
+    mov     ax,     es:[bx + 15]
+    mov     dx,     es:[bx + 19]
+    mov     cx,     es:[bx + 12]
+    
+    call    _find_file
+    jc      _int21_4F.error
+
+_int21_4F.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     8
+    pop     bp
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     iretc
+
+_int21_4F.error:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     8
+    pop     bp
+    
+    mov     ax,     18
+    stc
+    
+    jmp     iretc
diff --git a/src/kernel/int23.asm b/src/kernel/int23.asm
new file mode 100644 (file)
index 0000000..b422cbb
--- /dev/null
@@ -0,0 +1,106 @@
+;******************************************************************************
+; @file             int23.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _regain_control_int23
+;******************************************************************************
+_regain_control_int23:
+
+    push    bp
+    mov     bp,     sp
+    
+    mov     bp,     word ptr [bp + 2]
+    mov     word ptr [bp - 3],  ax
+    
+    pop     ax
+    
+    mov     word ptr [bp - 1],  ax
+    mov     ax,     bp
+    
+    dec     ax
+    dec     ax
+    dec     ax
+    xchg    ax,     sp
+    
+    pushf
+    add     ax,     (4 + 7)
+    sub     ax,     bp
+    pop     ax
+    jz      _int23_ign_carry
+    
+    push    ax
+    popf
+
+_int23_ign_carry:
+
+    pop     ax
+    jnc     _int23_respawn
+    
+    xor     ah,     ah
+
+_int23_respawn:
+
+    pop     bp
+    jmp     _int21_dispatch
+
+;******************************************************************************
+; @function         _int23_handler
+;******************************************************************************
+global      _int23_handler
+_int23_handler:
+
+    stc
+    retf 0
+
+;******************************************************************************
+; @function          _spawn_int23
+;******************************************************************************
+global      _spawn_int23
+_spawn_int23:
+
+    mov     bp,     cs:[_user_sssp]
+    cli
+    
+    mov     ss,     cs:[_user_sssp + 2]
+    mov     sp,     bp
+    
+    sti
+    sub     sp,     8
+    
+    mov     ax,     cs:[_user_ax]
+    mov     bp,     cs:[_user_bp]
+    
+    push    ss
+    push    bp
+    
+    mov     bp,     sp
+    add     bp,     4
+    
+    mov     word ptr [bp],      HEX (23CD)
+    mov     byte ptr [bp + 2],  HEX (9A)
+    mov     word ptr [bp + 3],  offset _regain_control_int23
+    mov     word ptr [bp + 5],  cs
+    
+    xchg    word ptr [bp - 4],  bp
+    clc
+    
+    retf
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _user_sssp
+_user_sssp:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _user_ax
+_user_ax:                       dw      HEX (0000)
+
+global      _user_bp
+_user_bp:                       dw      HEX (0000)
diff --git a/src/kernel/invalid.asm b/src/kernel/invalid.asm
new file mode 100644 (file)
index 0000000..aa8a9f8
--- /dev/null
@@ -0,0 +1,144 @@
+;******************************************************************************
+; @file             invalid.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _invalid_handler
+;******************************************************************************
+global      _invalid_handler
+_invalid_handler:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    ax
+    push    bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're within the kernel then we'll blue screen.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_curr_psp],        0
+    jne     _invalid_handler.no_clear
+
+_invalid_handler.clear:
+
+    mov     ax,     HEX (0600)
+    mov     bh,     HEX (1F)
+    xor     cx,     cx
+    mov     dx,     HEX (1850)
+    int     HEX (10)
+    
+    mov     ah,     HEX (02)
+    xor     bh,     bh
+    xor     dx,     dx
+    int     HEX (10)
+    
+    jmp     _invalid_handler.init
+
+_invalid_handler.no_clear:
+
+    call    _crlf
+
+_invalid_handler.init:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the data segment is the dame as the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print our first message.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     offset _invalid_handler.msg
+    call    _writestr
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print a newline.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+
+_invalid_handler.loop:
+
+    cmp     si,     12 * 2
+    jae     _invalid_handler.done
+    
+    mov     ax,     si
+    xor     dx,     dx
+    
+    mov     cx,     12
+    div     cx
+    
+    and     dx,     dx
+    jnz     _invalid_handler.print
+    
+    call    _crlf
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+
+_invalid_handler.print:
+
+    mov     ax,     word ptr [bp + si]
+    call    _writehex
+    
+    inc     si
+    inc     si
+    
+    mov     ax,     si
+    xor     dx,     dx
+    
+    mov     cx,     12
+    div     cx
+    
+    and     dx,     dx
+    jz      _invalid_handler.loop
+    
+    mov     al,     ' '
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    call    _writechr
+    
+    jmp     _invalid_handler.loop
+
+_invalid_handler.done:
+
+    call    _crlf
+    call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we're within the kernel we don't want to try quiting
+    ;; the program.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_curr_psp],        0
+    je      _invalid_handler.reboot
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Let's try and exit the current process.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (4C7F)
+    int     HEX (21)
+
+_invalid_handler.reboot:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call error with our ending message.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "Press any key to reboot...",   HEX (00)
+
+_invalid_handler.msg:
+
+    db      "Trap to vector 6: Invalid opcode",     HEX (00)
diff --git a/src/kernel/kernel.asm b/src/kernel/kernel.asm
new file mode 100644 (file)
index 0000000..dc23c0f
--- /dev/null
@@ -0,0 +1,878 @@
+;******************************************************************************
+; @file             kernel.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Interrupt vectors.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     DIVIDE_VECTOR               0x00                                    ; Divide Interrupt Vector.
+%define     INVALID_VECTOR              0x06                                    ; Invalid Opcode Interrupt Vector.
+%define     REBOOT_VECTOR               0x19                                    ; Warm Reboot Interrupt Vector.
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; DOS Interrupt Vectors.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%define     INT20_VECTOR                0x20                                    ; Current Process Terminate Vector.
+%define     INT21_VECTOR                0x21                                    ; DOS API Vector.
+%define     INT22_VECTOR                0x22                                    ; Program Terminate Interrupt Vector.
+%define     INT23_VECTOR                0x23                                    ; CTRL-C Interrupt Vector.
+
+;******************************************************************************
+; @function         _all_read
+;******************************************************************************
+global      _all_read
+_all_read:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the value that's in the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data segment with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the drive no.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [_drive_no],    dl
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the stack segment with the value stored in bx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ss,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We should only need a little room for the stack so set the
+    ;; stack pointer to 2048.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     sp,     HEX (0800)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to out main code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _real_start
+
+;******************************************************************************
+; @function         _clear_kbd
+;******************************************************************************
+;_clear_kbd:
+;
+;    push    ax
+;
+;_clear_kbd.loop:
+;
+;    mov     ah,     HEX (01)
+;    int     HEX (16)
+;    jz      _clear_kbd.done
+;    
+;    xor     ah,     ah
+;    int     HEX (16)
+;    
+;    jmp     short   _clear_kbd.loop
+;
+;_clear_kbd.done:
+;
+;    pop     ax
+;    ret
+
+;******************************************************************************
+; @function         _int20_handler
+;******************************************************************************
+_int20_handler:
+
+    mov     ax,     HEX (4C00)
+    jmp     _int21_dispatch
+
+;******************************************************************************
+; @function         _int22_handler
+;******************************************************************************
+_int22_handler:
+
+    ret
+
+;******************************************************************************
+; @function         _reboot_handler
+;******************************************************************************
+_reboot_handler:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Disable interrupts and clear the direction flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cli
+    cld
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    ds
+    push    si
+    push    di
+    push    ax
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the data and extra segments with the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Setup si and bx to point to our list and list end.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _interrupts_list
+    mov     bx,     offset _interrupts_list_end
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+
+_reboot_handler.loop:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we're not at the end of our interrupts list.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     si,     bx
+    je      _reboot_handler.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a byte from DS:SI to the al register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value into the DI register and multiple by 4 to get the
+    ;; correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     ax
+    shl     di
+    shl     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value of DS:SI to ES:DI twice.
+    ;;
+    ;;     Note: This will increment both the SI and DI registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    movsw
+    movsw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop back for the next entry (if there is one).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _reboot_handler.loop
+
+_reboot_handler.done:
+
+    pop     cx
+    pop     ax
+    pop     di
+    pop     si
+    pop     ds
+    pop     es
+    
+    int     HEX (19)
+
+;******************************************************************************
+; @function         _real_start
+;******************************************************************************
+_real_start:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the data segment is initialized to the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;mov     ax,     cs
+    ;mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First we'll move the value in the stack pointer into the ax register
+    ;; and clear the dx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     sp
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Do we have any left over bytes (size % 16).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so we got the right segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jz      .L8
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Yep, we have linguring bytes so increase the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the zero flag is set then we have overflowed
+    ;; (greater than 65535 bytes)
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     .L8
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Just for good measure set the data segment to the code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print an error.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _error
+    db      "segment overflow",     HEX (0D),   HEX (0A),   HEX (00)
+
+.L8:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Now that we have the amount of segments that the stack pointer takes
+    ;; up we need to add the stack segment to get the first available segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ss
+    add     ax,     bx
+    
+    mov     [_free_seg],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the total memory (in KBs) and convert it to paragrahps for the
+    ;; maximum segment value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    mov     cl,     6
+    shl     ax,     cl
+    
+    mov     [_max_seg],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the di register with our free segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     [_free_seg]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register ready for stosw.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+
+_clear_memory:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we've reached out max segment then we've cleared all our
+    ;; free memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     di,     [_max_seg]
+    je      _check_disks
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve some registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    cx
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment with the value in the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll be clearing 128 words (i.e 128 * 2) at a time.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     128
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the value in the ax register into es:di unitl cx is zero.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    rep     stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore our registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add 16 to get the next segment.
+    ;;
+    ;;     E.g. (0050:00ff -> 0x05ff) + 1 = 0060:0000 -> 0x0600.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     di,     16
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop back to the clear the segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _clear_memory
+
+_check_disks:
+
+    mov     cx,     2
+
+.L10:
+
+    and     cx,     cx
+    jz      .L13
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The very first thing we do is allocate at least 1 disk for use
+    ;; with floppies.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (80)
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try to allocate memory, this should never return if it fails.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _kmalloc
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Push the address to the vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    mov     ax,     offset _vec_parts
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll start adding info to the segment starting at 0.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First, thing we need is a place to store the current directory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     65
+    xor     dx,     dx
+    
+    call    _kmalloc
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Start in the root of the disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We need a scratch buffer for the disk so allocate one.
+    ;;
+    ;; Floppies are typically 512 bytes per sector and there's
+    ;; usually no more than 2 sectors per cluster so
+    ;; allocating 1024 (2 sectors) should be fine.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1024
+    xor     dx,     dx
+    
+    call    _kmalloc
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Decrement cx and loop back for next drive.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    dec     cx
+    jmp     .L10
+
+.L13:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out ah and put the drive number in al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ah,     ah
+    mov     al,     cs:[_drive_no]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Are we booted from a floppy or hard disk?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    al,     HEX (80)
+    jnz     .L9
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the selected disk as the drive number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cs:[_selected_disk],    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Okay, we are booted from a floppy so we need to figure out which
+    ;; address it is within our _Vec_parts "structure".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    
+    mov     ax,     cs:[_vec_parts]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try and read the drive.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    
+    mov     ax,     ss
+    mov     es,     ax
+    xor     bx,     bx
+    
+    mov     ax,     HEX (0201)
+    mov     cx,     HEX (0001)
+    xor     dh,     dh
+    mov     dl,     cs:[_drive_no]
+    stc
+    int     HEX (13)
+    pop     es
+    jnc     .L11
+    
+    call    _error
+    db      "panic: failed to read boot drive",     HEX (0D),   HEX (0A),   HEX (00)
+
+.L11:
+
+    cmp     byte ptr ss:[bx + 0],       HEX (EB)
+    jne     .L10
+    
+    cmp     byte ptr ss:[bx + 2],       HEX (90)
+    jne     .L10
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Next we'll copy the BPB to our "structure".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ds
+    
+    mov     ax,     ss
+    mov     ds,     ax
+    
+    mov     si,     bx
+    add     si,     11
+    
+    mov     cx,     25
+    rep     movsb
+    
+    pop     ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the drive number.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     cs:[_drive_no]
+    stosb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Floppies should be FAT12 so pad with zeros.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    xor     dx,     dx
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset of the first FAT.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ss:[bx + 28]
+    mov     di,     ss:[bx + 30]
+    
+    add     si,     ss:[bx + 14]
+    adc     di,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     di
+    pop     di
+    
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     cx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Repush di and reset the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    
+    push    di
+    mov     di,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors both FATs require.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     al,     ss:[bx + 16]
+    cbw
+    mul     word ptr ss:[bx + 22]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the FAT offset to get the root directory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     di
+    pop     di
+    
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     cx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Repush di and reset the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    
+    push    di
+    mov     di,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate how many sectors the root directory requires.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (0020)
+    mul     word ptr ss:[bx + 17]
+    div     word ptr ss:[bx + 11]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Adjust the root offset to get the data offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     ax
+    adc     di,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in di to dx and restore di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     di
+    pop     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the offset for later use.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    mov     ax,     dx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Floppies shouldn't have a sector mask or shift.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Figure out how big a cluster is.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     ss:[bx + 11]
+    xor     dx,     dx
+    
+    xor     ch,     ch
+    mov     cl,     ss:[bx + 13]
+    
+    mul     cx
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We don't want to set the selected drive so jump to getting the
+    ;; hard disk paritions.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     .L12
+
+.L9:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; For hard disks we always start at disk 2 (C:).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     2
+    mov     cs:[_selected_disk],    ax
+
+.L12:
+
+    call    _get_hard_disk_partitions
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Debugging!!!
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;mov     ax,     cs:[_clust_size]
+    ;call    _writehex
+    ;call    _crlf
+    ;
+    ;mov     ax,     cs:[_selected_disk]
+    ;xor     dx,     dx
+    ;
+    ;mov     cx,     2
+    ;mul     cx
+    ;
+    ;mov     bx,     ax
+    ;
+    ;mov     ax,     cs:[_vec_parts]
+    ;mov     es,     ax
+    ;
+    ;mov     ax,     es:[bx]
+    ;mov     es,     ax
+    ;
+    ;mov     ax,     es:[HEX (0000)]
+    ;call    _writehex
+    ;call    _crlf
+    ;
+    ;mov     ax,     es:[HEX (0002)]
+    ;call    _writehex
+    ;call    _crlf
+    ;
+    ;mov     ax,     es:[HEX (0004)]
+    ;call    _writehex
+    ;call    _crlf
+    ;
+    ;xor     ah,     ah
+    ;mov     al,     es:[HEX (0006)]
+    ;call    _writehex
+    ;call    _crlf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reserve 1024 bytes for a fat segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1024
+    xor     dx,     dx
+    
+    call    _kmalloc
+    mov     cs:[_fat_seg],      ax
+
+_setup_interrupts:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Setup si and bx to point to our list and list end.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     offset _interrupts_list
+    mov     bx,     offset _interrupts_list_end
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the extra segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+
+.L4:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we're not at the end of our interrupts list.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     si,     bx
+    je      .L5
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a byte from DS:SI to the al register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value into the DI register and multiple by 4 to get the
+    ;; correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     ax
+    shl     di
+    shl     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the address at the memory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     es:[di]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value of DS:SI to ES:DI.
+    ;;
+    ;;     Note: This will increment both the SI and DI registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    movsw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the address we previously got.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [si - 2],   dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the segment at the memory offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     es:[di]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The segment of the new interrupt will be our code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es:[di],    cs
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save the segment we previously got.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [si],       dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to the SI register to account for the saved segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     si,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Loop back for the next entry (if there is one).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   .L4
+
+.L5:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-enable interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sti
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Figure out how much memory we should allocate per program.  If we
+    ;; have less than 256KB of memory then we'll divide by 4.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    int     HEX (12)
+    
+    mov     cl,     2
+    shl     ax,     cl
+    
+    cmp     ax,     HEX (0400)
+    jae     .L17
+    
+    mov     cs:[_max_prog_alloc],       ax
+
+.L17:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the data segment is actually initialized to the
+    ;; code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We also want to make sure the extra segment is initialized to the
+    ;; code segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out all other registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    xor     di,     di
+    xor     ax,     ax
+    xor     bx,     bx
+    xor     cx,     cx
+    xor     dx,     dx
+
+.L14:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Execute command.com.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     offset _app_name
+    mov     bx,     offset _param_blk
+    
+    mov     ax,     HEX (4B00)
+    int     HEX (21)
+    jc      .L7
+    
+    jmp     .L16
+
+.L7:
+
+    mov     bx,     offset _app_errmsg
+    
+    call    _writestr
+    call    _crlf
+
+.L16:
+
+    cli
+    hlt
+    
+    jmp     .L16
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Start up file (tranditionally command.com).
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_app_errmsg:                    db      "Bad or missing Command Interpreter",       HEX (00)
+
+_app_name:                      db      "\\command.com",        HEX (00)
+_param_blk:                     db      16      dup (0)
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+align   4
+_interrupts_list:
+
+    db      DIVIDE_VECTOR
+    dw      _divide_handler,    HEX (0000)
+    
+    db      INVALID_VECTOR
+    dw      _invalid_handler,   HEX (0000)
+    
+    db      REBOOT_VECTOR
+    dw      _reboot_handler,    HEX (0000)
+    
+    db      INT20_VECTOR
+    dw      _int20_handler,     HEX (0000)
+    
+    db      INT21_VECTOR
+    dw      _int21_dispatch,    HEX (0000)
+    
+    db      INT22_VECTOR
+    dw      _int22_handler,     HEX (0000)
+    
+    db      INT23_VECTOR
+    dw      _int23_handler,     HEX (0000)
+
+_interrupts_list_end:
diff --git a/src/kernel/kmalloc.asm b/src/kernel/kmalloc.asm
new file mode 100644 (file)
index 0000000..ba57b6d
--- /dev/null
@@ -0,0 +1,127 @@
+;******************************************************************************
+; @file             kmalloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _kmalloc
+;******************************************************************************
+global      _kmalloc
+_kmalloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax and dx registers should be setup with the size we want
+    ;; to allocate so convert it to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _kmalloc.ok
+
+_kmalloc.inc:
+
+    inc     ax
+    jz      _kmalloc.error
+
+_kmalloc.ok:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try and allocate the memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    
+    call    _alloc_mem
+    jc      _kmalloc.error
+    
+    push    ax
+    push    bx
+    
+    dec     ax
+    mov     es,     ax
+    
+    xor     bx,     bx
+    mov     cx,     es:[bx + 3]
+    
+    pop     bx
+    pop     ax
+    
+    push    ax
+    mov     es,     ax
+
+_kmalloc.loop:
+
+    xor     di,     di
+    
+    push    ax
+    push    cx
+    
+    xor     al,     al
+    mov     cx,     16
+    rep     stosb
+    
+    pop     cx
+    pop     ax
+    
+    inc     ax
+    mov     es,     ax
+    
+    loop    _kmalloc.loop
+
+_kmalloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_kmalloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we fail to get memory in here then there's something wrong
+    ;; so just error out.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    call    _error
+    db      "panic: failed to alloc memory in kmalloc",     HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/kernel/krealloc.asm b/src/kernel/krealloc.asm
new file mode 100644 (file)
index 0000000..82d3ec0
--- /dev/null
@@ -0,0 +1,223 @@
+;******************************************************************************
+; @file             xrealloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _krealloc
+;******************************************************************************
+global      _krealloc
+_krealloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have valid memory as a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _krealloc.calc
+    
+    mov     di,     bx
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _krealloc.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _krealloc.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _krealloc.error
+
+_krealloc.calc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The ax and dx registers should be setup with the size we want
+    ;; to allocate so convert it to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _krealloc.ok
+
+_krealloc.inc:
+
+    inc     ax
+    jz      _krealloc.error
+
+_krealloc.ok:
+
+    mov     si,     ax
+    
+    and     bx,     bx
+    jz      _krealloc.alloc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First. lets try and resize the memory block.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    mov     es,     bx
+    mov     bx,     si
+    call    _resize_mem
+    
+    pop     es
+    pop     bx
+    jnc     _krealloc.done
+
+_krealloc.alloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Try and allocate the memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    
+    mov     bx,     si
+    call    _alloc_mem
+    
+    pop     bx
+    jc      _krealloc.error
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Only copy existing data if there was an original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     bx
+    
+    and     di,     di
+    jz      _krealloc.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers that copy will clobber.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ds
+    
+    mov     di,     bx
+    mov     ds,     di
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    mov     cx,     word ptr es:[di + 3]
+    mov     es,     ax
+    
+    cmp     cx,     bx
+    jb      _krealloc.copy
+    
+    mov     cx,     bx
+
+_krealloc.copy:
+
+    xor     si,     si
+    xor     di,     di
+    
+    push    cx
+    
+    mov     cx,     16
+    rep     movsb
+    
+    pop     cx
+    
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    mov     di,     ds
+    inc     di
+    mov     ds,     di
+    
+    loop    _krealloc.copy
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers that copy clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     si
+
+_krealloc.free:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we reached this point then free the original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    call    _free_mem
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_krealloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_krealloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we fail to get memory in here then there's something wrong
+    ;; so just error out.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    call    _error
+    db      "panic: failed to alloc memory in krealloc",    HEX (0D),   HEX (0A),   HEX (00)
diff --git a/src/kernel/mangle.asm b/src/kernel/mangle.asm
new file mode 100644 (file)
index 0000000..027ff0a
--- /dev/null
@@ -0,0 +1,172 @@
+;******************************************************************************
+; @file             mangle.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function        _mangle_dos_name
+;******************************************************************************
+global      _mangle_dos_name
+_mangle_dos_name:
+
+    push    ax
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     cx,     cs
+    mov     es,     cx
+    
+    mov     di,     offset _mangled_name
+    mov     cx,     11
+
+_mangle_dos_name.loop:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jna     _mangle_dos_name.end
+    
+    cmp     al,     '\\'
+    je      _mangle_dos_name.end
+    
+    cmp     al,     '.'
+    je      _mangle_dos_name.is_period
+    
+    cmp     al,     HEX (61)
+    jb      _mangle_dos_name.no_conv
+    
+    cmp     al,     HEX (7A)
+    ja      _mangle_dos_name.no_conv
+    
+    mov     dl,     HEX (20)
+    not     dl
+    
+    and     al,     dl
+
+_mangle_dos_name.no_conv:
+
+    mov     bx,     offset _invalid_chars
+    mov     ah,     cl
+    
+    cmp     ax,     HEX (0BE5)
+    jne     _mangle_dos_name.check
+    
+    mov     al,     HEX (05)
+
+_mangle_dos_name.check:
+
+    cmp     byte ptr cs:[bx],   0
+    je      _mangle_dos_name.store
+    
+    cmp     byte ptr cs:[bx],   al
+    je      _mangle_dos_name.error
+    
+    inc     bx
+    jmp     short   _mangle_dos_name.check
+
+_mangle_dos_name.store:
+
+    stosb
+    loop    _mangle_dos_name.loop
+
+_mangle_dos_name.find_end:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jna     _mangle_dos_name.end
+    
+    cmp     al,     '\\'
+    jne     _mangle_dos_name.find_end
+
+_mangle_dos_name.end:
+
+    mov     al,     ' '
+    rep     stosb
+
+_mangle_dos_name.done:
+
+    mov     bx,     offset _mangled_name
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    clc
+    ret
+
+_mangle_dos_name.is_period:
+
+    cmp     cx,     11
+    jb      _mangle_dir.period_check
+    
+    mov     al,     '.'
+    stosb
+    
+    dec     cx
+    jmp     _mangle_dos_name.loop
+
+_mangle_dir.period_check:
+
+    cmp     di,     offset _mangled_name
+    je      _mangle_dir.add_period
+    
+    cmp     byte ptr es:[di - 1],   '.'
+    jne     _mangle_dir.need_padding
+
+_mangle_dir.add_period:
+
+    mov     al,     '.'
+    stosb
+    
+    dec     cx
+    jmp     _mangle_dos_name.loop
+
+_mangle_dir.need_padding:
+
+    mov     al,     ' '
+
+_mangle_dos_name.period_loop:
+
+    cmp     cx,     3
+    jbe     _mangle_dos_name.loop
+    
+    stosb
+    loop    _mangle_dos_name.period_loop
+
+_mangle_dos_name.error:
+
+    mov     di,     offset _mangled_name
+    xor     al,     al
+    
+    mov     cx,     11
+    rep     stosb
+    
+    mov     bx,     offset _mangled_name
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     ax
+    
+    stc
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_invalid_chars:                 db      "\"*+,/:;<=>?[]|",      HEX (00)
+_mangled_name:                  db      12      dup (0)
diff --git a/src/kernel/mem.asm b/src/kernel/mem.asm
new file mode 100644 (file)
index 0000000..477a423
--- /dev/null
@@ -0,0 +1,366 @@
+;******************************************************************************
+; @file             mem.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _alloc_mem
+;******************************************************************************
+global      _alloc_mem
+_alloc_mem:
+
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    mov     ax,     cs:[_free_seg]
+    mov     es,     ax
+    
+    push    es
+    
+    mov     ax,     bx
+    xor     di,     di
+
+_alloc_mem.search:
+
+    mov     cx,     es
+    
+    cmp     cx,     cs:[_free_seg]
+    jb      _alloc_mem.error
+    
+    cmp     cx,     cs:[_max_seg]
+    jae     _alloc_mem.error
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _alloc_mem.check
+    
+    jmp     short   _alloc_mem.next
+
+_alloc_mem.check:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _alloc_mem.check2
+    
+    jmp     short   _alloc_mem.next
+
+_alloc_mem.check2:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _alloc_mem.retry
+    
+_alloc_mem.next:
+
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    dec     ax
+    jnz     _alloc_mem.search
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _alloc_mem.check3
+    
+    cmp     si,     cs:[_free_seg]
+    jb      _alloc_mem.error
+    
+    cmp     si,     cs:[_max_seg]
+    jae     _alloc_mem.error
+    
+    jmp     short   _alloc_mem.success
+
+_alloc_mem.check3:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _alloc_mem.check4
+    
+    jmp     short   _alloc_mem.success
+
+_alloc_mem.check4:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _alloc_mem.success
+
+_alloc_mem.retry:
+
+    mov     cx,     es:[di + 3]
+    inc     cx
+    
+    mov     si,     es
+    add     si,     cx
+    mov     es,     si
+    
+    pop     si
+    push    es
+    
+    mov     ax,     bx
+    jmp     _alloc_mem.search
+
+_alloc_mem.success:
+
+    xor     di,     di
+    pop     es
+    
+    mov     byte ptr es:[di],       'M'
+    mov     byte ptr es:[di + 1],   'C'
+    mov     byte ptr es:[di + 2],   'B'
+    
+    mov     word ptr es:[di + 3],   bx
+    mov     ax,     cs:[_curr_psp]
+    mov     word ptr es:[di + 5],   ax
+    
+    mov     ax,     es
+    inc     ax
+    
+    clc
+    jmp     short   _alloc_mem.done
+
+_alloc_mem.error:
+
+    mov     bx,     es
+    pop     ax
+    sub     bx,     ax
+    
+    mov     ax,     8
+    stc
+
+_alloc_mem.done:
+
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+;******************************************************************************
+; @function          _free_mem
+;******************************************************************************
+global      _free_mem
+_free_mem:
+
+    push    bx
+    push    cx
+    push    di
+    push    es
+    
+    mov     di,     es
+    
+    and     di,     di
+    jz      _free_mem.error
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _free_mem.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _free_mem.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _free_mem.error
+    
+    xor     al,     al
+    mov     cx,     16
+    rep     movsb
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     short   _free_mem.done
+    
+_free_mem.error:
+
+    mov     ax,     9
+    stc
+
+_free_mem.done:
+
+    pop     es
+    pop     di
+    pop     cx
+    pop     bx
+    ret
+
+;******************************************************************************
+; @function         _resize_mem
+;******************************************************************************
+global      _resize_mem
+_resize_mem:
+
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    
+    mov     di,     es
+    
+    and     di,     di
+    jz      _resize_mem.error
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _resize_mem.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _resize_mem.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _resize_mem.error
+    
+    mov     cx,     word ptr es:[di + 3]
+    
+    cmp     cx,     bx
+    jae     _resize_mem.success
+    
+    mov     di,     es
+    add     di,     cx
+    mov     es,     di
+    
+    mov     ax,     bx
+    sub     ax,     cx
+    
+    xor     di,     di
+
+_resize_mem.search:
+
+    mov     cx,     es
+    
+    cmp     cx,     cs:[_max_seg]
+    jae     _resize_mem.ins
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _resize_mem.check
+    
+    jmp     short   _resize_mem.next
+
+_resize_mem.check:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _resize_mem.check2
+    
+    jmp     short   _resize_mem.next
+
+_resize_mem.check2:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _resize_mem.ins
+
+_resize_mem.next:
+
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    dec     ax
+    jnz     _resize_mem.search
+    
+    cmp     si,     cs:[_max_seg]
+    jae     _resize_mem.max
+    
+    cmp     byte ptr es:[di],   'M'
+    je      _resize_mem.check3
+    
+    jmp     short   _resize_mem.success
+
+_resize_mem.check3:
+
+    cmp     byte ptr es:[di + 1],   'C'
+    je      _resize_mem.check4
+    
+    jmp     short   _resize_mem.success
+
+_resize_mem.check4:
+
+    cmp     byte ptr es:[di + 2],   'B'
+    je      _resize_mem.ins
+
+_resize_mem.success:
+
+    pop     es
+    
+    mov     di,     es
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    mov     word ptr es:[di + 3],   bx
+    
+    mov     di,     es
+    inc     di
+    mov     es,     di
+    
+    mov     ax,     es
+    clc
+    
+    jmp     short   _resize_mem.done
+
+_resize_mem.max:
+
+    mov     bx,     cs:[_max_seg]
+    jmp     short   _resize_mem.got_seg
+
+_resize_mem.ins:
+
+    mov     bx,     es
+
+_resize_mem.got_seg:
+
+    pop     es
+    
+    mov     ax,     es
+    sub     bx,     ax
+    
+    push    es
+    
+    mov     di,     es
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    mov     word ptr es:[di + 3],   bx
+    
+    mov     ax,     8
+    stc
+    
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+_resize_mem.error:
+
+    mov     ax,     9
+    stc
+    
+    pop     es
+
+_resize_mem.done:
+
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _free_seg
+_free_seg:                      dw      HEX (0000)
+
+global      _max_seg
+_max_seg:                       dw      HEX (0000)
diff --git a/src/kernel/prog.asm b/src/kernel/prog.asm
new file mode 100644 (file)
index 0000000..6e76d5a
--- /dev/null
@@ -0,0 +1,404 @@
+;******************************************************************************
+; @file             prog.asm
+;******************************************************************************
+%ifndef     HEX
+% define    HEX(y)                      0x##y
+%endif
+
+;******************************************************************************
+; @function         _alloc_prog_mem
+;******************************************************************************
+_alloc_prog_mem:
+
+    push    bx
+    push    cx
+    
+    cmp     ax,     dx
+    jb      _alloc_prog_mem.error
+
+    mov     cl,     4
+    
+    mov     bx,     ax
+    shl     bx,     cl
+    
+    sub     bx,     4
+    
+    mov     cs:[_child_sssp],   bx
+    mov     bx,     ax
+    
+    call    _alloc_mem
+    jnc     _alloc_prog_mem.done
+
+_alloc_prog_mem.error:
+
+    pop     cx
+    pop     bx
+    
+    mov     ax,     8
+    stc
+    
+    ret
+
+_alloc_prog_mem.done:
+
+    pop     cx
+    pop     bx
+    
+    clc
+    ret
+
+
+;******************************************************************************
+; @function         _load_program
+;******************************************************************************
+global      _load_program
+_load_program:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    call    _open_file
+    jnc     _load_program.got_file
+    
+    add     sp,     2
+    stc
+    
+    pop     bp
+    ret
+
+_load_program.got_file:
+
+    mov     word ptr [bp - 2],      ax
+    
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    push    ds
+    
+    mov     ax,     HEX (4202)
+    mov     bx,     word ptr [bp - 2]
+    xor     cx,     cx
+    xor     dx,     dx
+    
+    call    _seek_file
+    jc      _load_program.error
+    
+    add     ax,     HEX (0200)                              ; Minimum of 8KB for the stack.
+    adc     dx,     0
+    
+    mov     cx,     16
+    div     cx
+    
+    and     dx,     dx
+    jz      _load_program.got_size
+    
+    inc     ax
+    jnz     _load_program.got_size
+    
+    mov     ax,     8
+    jmp     _load_program.error
+
+_load_program.got_size:
+
+    push    ax
+    
+    mov     ax,     HEX (4200)
+    mov     bx,     word ptr [bp - 2]
+    xor     cx,     cx
+    xor     dx,     dx
+    
+    call    _seek_file
+    pop     dx
+    jc      _load_program.error
+    
+    mov     ax,     cs:[_max_prog_alloc]
+    
+    call    _alloc_prog_mem
+    jnc     _load_program.mem_ok
+
+_load_program.no_mem:
+
+    push    ax
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    
+    mov     bx,     offset _load_program.errmsg
+    call    _writestr
+    
+    pop     ax
+    jmp     _load_program.error
+
+_load_program.mem_ok:
+
+    mov     cs:[_child_sssp + 2],   ax
+    
+    mov     cs:[_child_csip + 2],   ax
+    mov     word ptr cs:[_child_csip],      HEX (0100)
+    
+    mov     es,     ax
+    mov     word ptr es:[HEX (00)],     HEX (20CD)
+    
+    mov     es:[HEX (02)],      ax
+    mov     word ptr es:[HEX (80)],     0
+    
+    mov     ax,     cs:[_curr_psp]
+    mov     es:[HEX (16)],      ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Ensure there's a 0 at the bottom of the stack so a local return call
+    ;; will execute the INT 20h instruction at [cs:0] and the initial value
+    ;; of ax.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     cs:[_child_sssp]
+    
+    xor     ax,     ax
+    stosw
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Point DTA at PSP:80h.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr cs:[_disk_transfer_addr],          HEX (80)
+    mov     word ptr cs:[_disk_transfer_addr + 2],      es
+    
+    mov     cs:[_curr_psp],     es
+    mov     bx,     word ptr [bp - 2]
+    
+    mov     ax,     es
+    mov     ds,     ax
+    
+    push    es
+    push    ds
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have any open files.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr cs:[_vec_files + 2],       0
+    je      _load_program.read_error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have a valid file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bx,     3
+    jb      _load_program.read_error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the correct file offset by subtracting 3.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    sub     bx,     3
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the offset into our vector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    dx
+    push    cx
+    
+    mov     ax,     bx
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    pop     cx
+    pop     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Intialize the es register with address of our vector entries
+    ;; and zero out bx for the counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the vector entry is zero then the file handle is invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     word ptr es:[bx],       0
+    je      _load_program.read_error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Re-initialize the extra segment but this time with the address
+    ;; of the vector entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     si,     si
+    
+    mov     ax,     es:[bx]
+    mov     es,     ax
+    
+    mov     cx,     HEX (0200)
+    mov     dx,     HEX (0100)
+    
+    mov     bx,     word ptr [bp - 2]
+
+_load_program.read:
+
+    call    _read_file
+    jc      _load_program.read_error
+    
+    and     ax,     ax
+    jz      _load_program.all_read
+    
+    shr     ax
+    shr     ax
+    shr     ax
+    shr     ax
+    
+    mov     di,     ds
+    add     di,     ax
+    mov     ds,     di
+    
+    jmp     short   _load_program.read
+
+_load_program.all_read:
+
+    pop     ds
+    pop     es
+    
+    mov     bx,     word ptr [bp - 2]
+    call    _close_file
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Save some interrupts.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    mov     es,     ax
+    
+    mov     ax,     es:[HEX (22) * 4]
+    mov     [HEX (0A)],     ax
+    
+    mov     ax,     es:[(HEX (22) * 4) + 2]
+    mov     [HEX (0C)],     ax
+    
+    mov     ax,     es:[HEX (23) * 4]
+    mov     [HEX (0E)],     ax
+    
+    mov     ax,     es:[(HEX (23) * 4) + 2]
+    mov     [HEX (10)],     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize "int 23h" with our default handler in case the
+    ;; user/program doesn't set the interrupt itself.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     offset _int23_handler
+    mov     es:[HEX (23) * 4],      bx
+    
+    mov     es:[(HEX (23) * 4) + 2],    cs
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the current psp address.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_curr_psp]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_load_program.read_error:
+
+    pop     ds
+    pop     es
+    
+    call    _free_mem
+
+_load_program.error:
+
+    mov     bx,     word ptr [bp - 2]
+    call    _close_file
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    stc
+    
+    pop     bp
+    ret
+
+_load_program.errmsg:           db      "Not enough memory to run program",     HEX (0D),   HEX (0A),   HEX (00)
+
+;******************************************************************************
+; @file             _start_program
+;******************************************************************************
+global      _start_program
+_start_program:
+
+    cli
+    
+    mov     ds,     ax
+    
+    mov     [HEX (42)],     sp
+    mov     [HEX (44)],     ss
+    
+    mov     es,     ax
+    
+    mov     ss,     cs:[_child_sssp + 2]
+    mov     sp,     cs:[_child_sssp]
+    
+    mov     dx,     cs:[_child_csip + 2]
+    mov     si,     cs:[_child_csip]
+    
+    mov     bp,     HEX (0900)
+    pop     bx
+    
+    mov     ax,     HEX (0202)
+    push    ax
+    
+    xor     ax,     ax
+    xchg    ax,     bx
+    
+    push    dx
+    push    si
+    
+    iret
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _curr_psp
+_curr_psp:                      dw      HEX (0000)
+
+global      _last_ret_val
+_last_ret_val:                  dw      HEX (0000)
+
+global      _child_sssp
+_child_sssp:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _child_csip
+_child_csip:
+
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+global      _max_prog_alloc
+_max_prog_alloc:                dw      HEX (1000)
diff --git a/src/kernel/query.asm b/src/kernel/query.asm
new file mode 100644 (file)
index 0000000..fac9ebc
--- /dev/null
@@ -0,0 +1,85 @@
+;******************************************************************************
+; @file             query.asm
+;******************************************************************************
+.386
+
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _query_cpu
+;******************************************************************************
+global      _query_cpu
+_query_cpu:
+
+    push    bx
+    push    cx
+    pushf
+    
+    xor     bx,     bx
+    
+    push    bx
+    popf
+    
+    pushf
+    pop     ax
+    
+    and     ax,     HEX (F000)
+    
+    cmp     ax,     HEX (F000)
+    jnz     _query_cpu.is_286
+    
+    mov     ax,     sp
+    xor     cx,     cx
+    
+    push    cx
+    inc     cx
+    
+    db      HEX (8F),   HEX (C1)
+    mov     sp,     ax
+    
+    or      cx,     cx
+    jz      _query_cpu.is_808x
+    
+    mov     bx,     cx
+    jmp     short   _query_cpu.done
+
+_query_cpu.is_808x:
+
+    mov     ax,     1
+    mov     cl,     64
+    shr     ax,     cl
+    
+    or      ax,     ax
+    jz      _query_cpu.is_86
+    
+    mov     bx,     1
+
+_query_cpu.is_86:
+
+    jmp     short   _query_cpu.done
+
+_query_cpu.is_286:
+
+    mov     bx,     2
+    mov     ax,     HEX (F000)
+    
+    push    ax
+    popf
+    
+    pushf
+    pop     ax
+    
+    test    ax,     HEX (F000)
+    jz      _query_cpu.done
+    
+    mov     bx,     3
+
+_query_cpu.done:
+
+    mov     ax,     bx
+    popf
+    pop     cx
+    pop     bx
+    ret
diff --git a/src/kernel/search.asm b/src/kernel/search.asm
new file mode 100644 (file)
index 0000000..4ce90fc
--- /dev/null
@@ -0,0 +1,263 @@
+;******************************************************************************
+; @file             search.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc file for our BPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _search_dos_dir
+;******************************************************************************
+global      _search_dos_dir
+_search_dos_dir:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     34
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 32],     bx
+    
+    mov     word ptr [bp - 20],     0
+    mov     word ptr [bp - 16],     0
+    
+    mov     bx,     ax
+    or      bx,     dx
+    
+    and     bx,     bx
+    jnz     _search_dos_dir.not_root
+    
+    mov     ax,     cs:[_root_start]
+    mov     dx,     cs:[_root_start + 2]
+
+_search_dos_dir.got_root:
+
+    mov     word ptr [bp - 30],     1
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    mov     ax,     32
+    xor     dx,     dx
+    
+    mov     cx,     cs:[_root_entries]
+    mul     cx
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    div     cx
+    
+    xchg    cx,     ax
+    dec     cx
+    
+    xor     dx,     dx
+    mov     word ptr [bp - 22],     cx
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.not_root:
+
+    mov     word ptr [bp - 30],     0
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    call    cs:[_convert_cluster]
+    jc      _search_dos_dir.not_found
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_sectors_per_cluster]
+    
+    mov     word ptr [bp - 34],     cx
+    dec     word ptr [bp - 34]
+
+_search_dos_dir.read:
+
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    mov     cx,     word ptr [bp - 24]
+    call    _read_sectors
+    
+    mov     ax,     cs:[_bytes_per_sector]
+    xor     dx,     dx
+    
+    mov     cx,     32
+    div     cx
+    xchg    cx,     ax
+    
+    xor     di,     di
+
+_search_dos_dir.search:
+
+    push    cx
+    mov     cx,     11
+    
+    cmp     byte ptr es:[di],       0
+    je      _search_dos_dir.advance
+    
+    cmp     byte ptr es:[di],       HEX (E5)
+    je      _search_dos_dir.advance
+    
+    push    si
+    push    di
+    push    ds
+    
+    mov     si,     cs
+    mov     ds,     si
+    
+    mov     si,     word ptr [bp - 32]
+    repe    cmpsb
+    
+    pop     ds
+    pop     di
+    pop     si
+    je      _search_dos_dir.found
+
+_search_dos_dir.advance:
+
+    pop     cx
+    
+    add     di,     32
+    loop    _search_dos_dir.search
+    
+    cmp     word ptr [bp - 30],     1
+    jne     _search_dos_dir.check
+    
+    mov     ax,     word ptr [bp - 22]
+    
+    and     ax,     ax
+    jz      _search_dos_dir.not_found
+    
+    dec     ax
+    mov     word ptr [bp - 22],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.check:
+
+    mov     ax,     word ptr [bp - 34]
+    
+    and     ax,     ax
+    jz      _search_dos_dir.next_clust
+    
+    dec     ax
+    mov     word ptr [bp - 34],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _search_dos_dir.read
+
+_search_dos_dir.next_clust:
+
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    call    cs:[_next_cluster]
+    jmp     _search_dos_dir.not_root
+
+_search_dos_dir.not_found:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     34
+    pop     bp
+    
+    mov     ax,     3
+    stc
+    
+    ret
+
+_search_dos_dir.found:
+
+    pop     cx
+    mov     si,     di
+    
+    mov     ax,     cs
+    mov     ds,     ax
+    mov     bx,     offset _file_info
+    
+    mov     ax,     es:[di + 26]
+    mov     [bx + 0],   ax
+    
+    mov     ax,     es:[di + 20]
+    mov     [bx + 2],   ax
+    
+    mov     ax,     es:[di + 28]
+    mov     [bx + 4],   ax
+    
+    mov     ax,     es:[di + 30]
+    mov     [bx + 6],   ax
+    
+    mov     al,     es:[di + 11]
+    mov     [bx + 8],   al
+    
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     34
+    pop     bp
+    
+    mov     ax,     offset _file_info
+    clc
+    
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_file_info:                     db      9       dup (0)
diff --git a/src/kernel/vector.asm b/src/kernel/vector.asm
new file mode 100644 (file)
index 0000000..d0bb687
--- /dev/null
@@ -0,0 +1,138 @@
+;******************************************************************************
+; @file             vector.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _vec_adjust
+;******************************************************************************
+_vec_adjust:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    bx
+    push    cx
+    push    dx
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_adjust.check:
+
+    mov     cx,     [bx + 2]
+    
+    cmp     cx,     word ptr [bp + 6]
+    ja      _vec_adjust.done
+
+_vec_adjust.check2:
+
+    and     cx,     cx
+    jnz     _vec_adjust.shift
+    
+    mov     cx,     16
+    jmp     short   _vec_adjust.set
+
+_vec_adjust.shift:
+
+    shl     cx
+
+_vec_adjust.set:
+
+    mov     [bx + 2],   cx
+
+_vec_adjust.alloc:
+
+    mov     ax,     2
+    xor     dx,     dx
+    
+    mul     cx
+    push    bx
+    
+    mov     bx,     [bx + 0]
+    call    _krealloc
+    
+    pop     bx
+    mov     [bx + 0],       ax
+
+_vec_adjust.done:
+
+    xor     ax,     ax
+    
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _vec_push
+;******************************************************************************
+global      _vec_push
+_vec_push:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    es
+    
+    mov     bx,     word ptr [bp + 4]
+
+_vec_push.alt:
+
+    mov     ax,     [bx + 4]
+    push    ax
+    
+    push    word ptr [bp + 4]
+    
+    call    _vec_adjust
+    add     sp,     4
+    
+    mov     word ptr [bp - 2],      ax
+    
+    and     ax,     ax
+    jnz     _vec_push.done
+
+_vec_push.set:
+
+    mov     ax,     [bx + 0]
+    mov     es,     ax
+    
+    mov     ax,     [bx + 4]
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     di,     ax
+    
+    mov     ax,     [bp + 6]
+    mov     es:[di],    ax
+    
+    mov     cx,     [bx + 4]
+    add     cx,     1
+    
+    mov     [bx + 4],   cx
+
+_vec_push.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     es
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    add     sp,     2
+    pop     bp
+    
+    ret
diff --git a/src/kernel/walk.asm b/src/kernel/walk.asm
new file mode 100644 (file)
index 0000000..98c1c4d
--- /dev/null
@@ -0,0 +1,110 @@
+;******************************************************************************
+; @file             walk.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _walk_path
+;******************************************************************************
+global      _walk_path
+_walk_path:
+
+    push    bx
+    
+    mov     ax,     cs:[_curr_cluster]
+    mov     dx,     cs:[_curr_cluster + 2]
+    
+    cmp     byte ptr [di],      '\\'
+    jne     _walk_path.not_root
+    
+    mov     ax,     cs:[_root_cluster]
+    mov     dx,     cs:[_root_cluster + 2]
+    
+    xor     cx,     cx
+    inc     di
+
+_walk_path.not_root:
+
+    push    ax
+    push    dx
+    
+    mov     si,     di
+
+_walk_path.skip:
+
+    lodsb
+    
+    cmp     al,     '\\'
+    je      _walk_path.skip
+    
+    dec     si
+    mov     di,     si
+
+_walk_path.find_end:
+
+    lodsb
+    
+    cmp     al,     ' '
+    jbe     _walk_path.end_path
+    
+    cmp     al,     '\\'
+    jne     _walk_path.find_end
+
+_walk_path.end_path:
+
+    xchg    si,     di
+    pop     dx
+    pop     ax
+    
+    mov     bx,     di
+    dec     bx
+    
+    cmp     bx,     si
+    je      _walk_path.done
+    
+    cmp     byte ptr [di - 1],      0
+    je      _walk_path.done
+    
+    call    _mangle_dos_name
+    jc      _walk_path.not_found
+    
+    call    _search_dos_dir
+    jc      _walk_path.not_found
+    
+    push    bx
+    push    es
+    
+    mov     bx,     cs
+    mov     es,     bx
+    mov     bx,     ax
+    
+    mov     ax,     es:[bx + 0]
+    mov     dx,     es:[bx + 2]
+    
+    mov     cl,     es:[bx + 8]
+    pop     es
+    pop     bx
+    
+    test    cl,     HEX (10)
+    jz      _walk_path.not_found
+    
+    cmp     byte ptr [di - 1],      '\\'
+    jne     _walk_path.done
+    
+    jmp     _walk_path.not_root
+
+_walk_path.not_found:
+
+    pop     bx
+    stc
+    
+    ret
+
+_walk_path.done:
+
+    pop     bx
+    clc
+    
+    ret
diff --git a/src/kernel/writechr.asm b/src/kernel/writechr.asm
new file mode 100644 (file)
index 0000000..b268990
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             writechr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         writechr
+;******************************************************************************
+global      _writechr
+_writechr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    bp                                                                  ; Some BIOSes destroy BP when the screen scrolls
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/kernel/writedec.asm b/src/kernel/writedec.asm
new file mode 100644 (file)
index 0000000..bd97d47
--- /dev/null
@@ -0,0 +1,53 @@
+;******************************************************************************
+; @file             writedec.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writedec
+;******************************************************************************
+global      _writedec
+_writedec:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    push    bp
+    
+    mov     bx,     10
+    xor     cx,     cx
+
+_writedec.cloop:
+
+    div     bx
+    inc     cx
+    
+    push    dx
+    xor     dx,     dx
+    
+    and     ax,     ax
+    jnz     _writedec.cloop
+
+_writedec.dloop:
+
+    pop     ax
+    
+    mov     ah,     HEX (0E)
+    add     al,     '0'
+    int     HEX (10)
+    
+    loop    _writedec.dloop
+
+_writedec.done:
+
+    pop     bp
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
diff --git a/src/kernel/writehex.asm b/src/kernel/writehex.asm
new file mode 100644 (file)
index 0000000..2b0eba7
--- /dev/null
@@ -0,0 +1,70 @@
+;******************************************************************************
+; @file             writehex.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function          _writehex
+;******************************************************************************
+global      _writehex
+_writehex:
+
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    di
+    
+    mov     di,     cs:[_writehex_num_digits]
+    mov     cl,     4
+
+_writehex.loop:
+
+    rol     ax,     cl
+    push    ax
+    and     al,     0b00001111
+    cmp     al,     10
+    jae     _writehex.high
+
+_writehex.low:
+
+    add     al,     HEX (30)
+    jmp     short   _writehex.ischar
+
+_writehex.high:
+
+    add     al,     HEX (37)
+
+_writehex.ischar:
+
+    mov     ah,     HEX (0E)
+    
+    push    bp
+    push    bx
+    
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+    
+    pop     bx
+    pop     bp
+    pop     ax
+    
+    dec     di
+    jnz     _writehex.loop
+
+_writehex.done:
+
+    pop     di
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+global      _writehex_num_digits
+_writehex_num_digits:           dw      HEX (0004)
diff --git a/src/kernel/writestr.asm b/src/kernel/writestr.asm
new file mode 100644 (file)
index 0000000..a849e2e
--- /dev/null
@@ -0,0 +1,75 @@
+;******************************************************************************
+; @file             writestr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _writestr
+;******************************************************************************
+global      _writestr
+_writestr:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    bx
+    push    si
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize si with bx
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump over our printing code to get the first character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _writestr.next
+
+_writestr.print:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Print the character to the screen.
+    ;;
+    ;;     AH = 0Eh - Teletype output
+    ;;     AL       - Character to print
+    ;;     BX       - Page number and color
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (0E)
+    mov     bx,     HEX (0007)
+    int     HEX (10)
+
+_writestr.next:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Load a character from si to al.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    lodsb
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached a NULL byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      al,     al
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Nope, so print the character.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jnz     _writestr.print
+
+_writestr.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    pop     si
+    pop     bx
+    pop     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/lib/Makefile.unix b/src/lib/Makefile.unix
new file mode 100644 (file)
index 0000000..a477ba8
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  crt
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for d in $(TARGETS); do \
+         if [ ! -d "$(OBJDIR)/$$d" ]; then mkdir -p "$(OBJDIR)/$$d"; fi; \
+         $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" all; \
+       done
+
+clean:
+       for d in $(TARGETS); do \
+         if [ -d "$(OBJDIR)/$$d" ]; then \
+           $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" clean; \
+         fi; \
+       done
diff --git a/src/lib/Makefile.w32 b/src/lib/Makefile.w32
new file mode 100644 (file)
index 0000000..08f1adf
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  crt
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%d in ($(TARGETS)) do ( \
+         ( if not exist "$(OBJDIR)/%%d" ( mkdir "$(OBJDIR)/%%d" ) ) & \
+         $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" all \
+       )
+
+clean:
+       for %%d in ($(TARGETS)) do ( \
+         if exist "$(OBJDIR)/%%d" ( \
+           $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" clean \
+         ) \
+       )
diff --git a/src/lib/crt/Makefile.unix b/src/lib/crt/Makefile.unix
new file mode 100644 (file)
index 0000000..f057cee
--- /dev/null
@@ -0,0 +1,25 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+ASMSRC              :=  $(shell find "$(SRCDIR)" -type f -name '*.asm' ! -name 'crt0*')
+ASMOBJ              :=  $(patsubst $(SRCDIR)/%, %, $(ASMSRC:.asm=.o))
+
+all: crt0.o libc.a
+
+clean:
+       for f in `find . -name '*.o'`; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       for f in `find . -name '*.lst'`; do if [ -f $$f ]; then rm -rf $$f; fi; done
+       if [ -f libc.a ]; then rm -rf libc.a; fi
+
+libc.a: $(ASMOBJ)
+       ../../utils/binutils/sar r $@ $^
+       ../../utils/binutils/sar s $@
+
+%.o: %.asm
+       if [ ! -d $(patsubst %/, %, $(dir $@)) ]; then mkdir -p $(patsubst %/, %, $(dir $@)); fi
+       ../../utils/binutils/sasm -I$(SRCDIR)/include -l $*.lst -o $@ $<
diff --git a/src/lib/crt/Makefile.w32 b/src/lib/crt/Makefile.w32
new file mode 100644 (file)
index 0000000..174fa3b
--- /dev/null
@@ -0,0 +1,25 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+VPATH               :=  $(SRCDIR)
+
+ASMSRC              :=  $(subst \,/,$(shell dir /s /b "$(SRCDIR)\\*.asm" | find "crt0.asm" /v))
+ASMOBJ              :=  $(patsubst $(SRCDIR)/%, %, $(ASMSRC:.asm=.o))
+
+all: crt0.o libc.a
+
+clean:
+       for /r %%f in (*.o) do ( if exist %%f ( del /q %%f ) )
+       for /r %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
+       if exist libc.a ( del /q libc.a )
+
+libc.a: $(ASMOBJ)
+       ../../utils/binutils/sar r $@ $^
+       ../../utils/binutils/sar s $@
+
+%.o: %.asm
+       if not exist $(patsubst %/, %, $(dir $@)) ( mkdir $(patsubst %/, %, $(dir $@)) )
+       ../../utils/binutils/sasm -I$(SRCDIR)/include -l $*.lst -o $@ $<
diff --git a/src/lib/crt/crt0.asm b/src/lib/crt/crt0.asm
new file mode 100644 (file)
index 0000000..7b22d2d
--- /dev/null
@@ -0,0 +1,306 @@
+;******************************************************************************
+; @file             crt0.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _start
+;******************************************************************************
+global      _start
+_start:
+
+    mov     ax,     sp
+    xor     dx,     dx
+    
+    mov     cx,     16
+    div     cx
+    
+    and     dx,     dx
+    jz      .L5
+    
+    inc     ax
+    jz      .L6
+
+.L5:
+
+    mov     bx,     ss
+    add     ax,     bx
+    
+    mov     bx,     ds
+    sub     ax,     bx
+    mov     bx,     ax
+    
+    mov     ah,     HEX (4A)
+    int     HEX (21)
+    
+    mov     di,     offset _program_name
+    mov     cx,     HEX (41)
+    
+    xor     al,     al
+    rep     stosb
+    
+    mov     di,     offset _cmd_line
+    mov     cx,     HEX (80)
+    
+    xor     al,     al
+    rep     stosb
+    
+    mov     di,     offset _argv
+    mov     cx,     132
+    
+    xor     al,     al
+    rep     stosb
+    
+    mov     word ptr [_argc],       0
+    
+    mov     di,     offset _cmd_line
+    mov     si,     HEX (80)
+    
+    xor     ah,     ah
+    lodsb
+    
+    and     ax,     ax
+    jz      .L4
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    mov     di,     offset _argv
+    add     di,     2
+    
+    mov     si,     offset _cmd_line
+    call    _get_args
+    
+.L4:
+
+    push    es
+    push    ds
+    
+    xor     bx,     bx
+    
+    mov     ah,     HEX (30)
+    int     HEX (21)
+    xchg    al,     ah
+    
+    cmp     ax,     HEX (0300)
+    jb      .L2
+    
+    mov     ax,     cs:[HEX (2C)]
+    
+    and     ax,     ax
+    jz      .L2
+    
+    mov     ds,     ax
+    xor     si,     si
+    
+    mov     di,     offset _program_name
+    xor     ax,     ax
+
+.L3:
+
+    mov     al,     [si]
+    inc     si
+    
+    and     al,     al
+    jnz     .L3
+    
+    mov     al,     [si]
+    inc     si
+    
+    and     al,     al
+    jnz     .L3
+    
+    mov     al,     [si]
+    
+    and     al,     al
+    jz      .L2
+    
+    add     si,     2
+    push    si
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    mov     bx,     offset _program_name
+
+.L2:
+
+    pop     ds
+    pop     es
+    
+    mov     di,     offset _argv
+    
+    mov     ax,     bx
+    stosw
+    
+    inc     word ptr [_argc]
+
+.L1:
+
+    mov     bx,     offset _argv
+    push    bx
+    
+    push    word ptr [_argc]
+    
+    call    _main
+    add     sp,     4
+
+.L6:
+
+    mov     ah,     HEX (4C)
+    int     HEX (21)
+
+;******************************************************************************
+; @function         _get_args
+;******************************************************************************
+_get_args:
+
+    push    ax
+    push    dx
+    push    si
+    push    di
+    
+    mov     dx,     HEX (20)
+
+_get_args.skip_spaces:
+
+    lodsb
+    
+    or      al,     al
+    jz      _get_args.done
+    
+    cmp     al,     ' '
+    je      _get_args.skip_spaces
+    
+    dec     si
+
+_get_args.loop:
+
+    mov     ax,     si
+    stosw
+    
+    inc     word ptr [_argc]
+    
+    push    dx
+    push    si
+    
+    call    _strchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      _get_args.done
+    
+    mov     si,     ax
+    
+    mov     byte ptr [si],  0
+    inc     si
+    
+    jmp     short   _get_args.skip_spaces
+
+_get_args.done:
+
+    xor     ax,     ax
+    stosw
+    
+    pop     di
+    pop     si
+    pop     dx
+    pop     ax
+    ret
+
+;******************************************************************************
+; @function         _strchr
+;******************************************************************************
+_strchr:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    si
+    push    bx
+    
+    mov     bx,     [bp + 6]
+    mov     si,     [bp + 4]
+
+_strchr.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strchr.done
+    
+    cmp     al,     bl
+    je      _strchr.found
+    
+    jmp     short   _strchr.loop
+
+_strchr.found:
+
+    mov     ax,     si
+    dec     ax
+    
+    pop     bx
+    pop     si
+    pop     bp
+    ret
+
+_strchr.done:
+
+    xor     ax,     ax
+    
+    pop     bx
+    pop     si
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _strlen
+;******************************************************************************
+_strlen:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    cx
+    push    si
+    push    di
+    
+    mov     si,     [bp + 4]
+    xor     cx,     cx
+
+_strlen.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strlen.done
+    
+    inc     cx
+    jmp     short   _strlen.loop
+
+_strlen.done:
+
+    mov     ax,     cx
+    
+    pop     di
+    pop     si
+    pop     cx
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_program_name:                  db      HEX (41)        dup (0)
+_cmd_line:                      db      HEX (80)        dup (0)
+
+_argv:                          db      132     dup (0)
+_argc:                          dw      HEX (0000)
diff --git a/src/lib/crt/ctype.asm b/src/lib/crt/ctype.asm
new file mode 100644 (file)
index 0000000..2bb0937
--- /dev/null
@@ -0,0 +1,1988 @@
+;******************************************************************************
+; @file             ctype.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _isalnum
+;******************************************************************************
+global      _isalnum
+_isalnum:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0001)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isalpha
+;******************************************************************************
+global      _isalpha
+_isalpha:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0002)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _iscntrl
+;******************************************************************************
+global      _iscntrl
+_iscntrl:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0004)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isdigit
+;******************************************************************************
+global      _isdigit
+_isdigit:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0008)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isgraph
+;******************************************************************************
+global      _isgraph
+_isgraph:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0010)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _islower
+;******************************************************************************
+global      _islower
+_islower:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0020)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isprint
+;******************************************************************************
+global      _isprint
+_isprint:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0040)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _ispunct
+;******************************************************************************
+global      _ispunct
+_ispunct:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0080)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isspace
+;******************************************************************************
+global      _isspace
+_isspace:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0100)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isupper
+;******************************************************************************
+global      _isupper
+_isupper:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0200)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _isxdigit
+;******************************************************************************
+global      _isxdigit
+_isxdigit:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __isbufR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     HEX (0400)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _tolower
+;******************************************************************************
+global      _tolower
+_tolower:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __tolowR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;******************************************************************************
+; @function         _toupper
+;******************************************************************************
+global      _toupper
+_toupper:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the base pointer with the stack pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the registers that will get clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the ax register with the value of the stack and zero
+    ;; out dx.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 4]
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Multiple by two to get the correct offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     2
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the offset of our "array".
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     offset __toupR
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add two to skip the first entry.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     ax,     2
+    adc     dx,     0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Divide by 16 to get a segment:offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add the code segment to the value in ax to get the correct segment.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     cs
+    add     ax,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; AX:DX should conatin the segment:offset of our "array" so
+    ;; set the extra segment to the calacaulted segment and dx to the
+    ;; calculated offset.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    mov     bx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es:[bx]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the registers that got clobbered
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+__isbufR:
+
+    dw      HEX (0000)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0104)
+    dw      HEX (0104)
+    dw      HEX (0104)
+    dw      HEX (0104)
+    dw      HEX (0104)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0004)
+    dw      HEX (0140)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (0459)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (0653)
+    dw      HEX (0653)
+    dw      HEX (0653)
+    dw      HEX (0653)
+    dw      HEX (0653)
+    dw      HEX (0653)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (0253)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (0473)
+    dw      HEX (0473)
+    dw      HEX (0473)
+    dw      HEX (0473)
+    dw      HEX (0473)
+    dw      HEX (0473)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (0073)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (00D0)
+    dw      HEX (0004)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+    dw      HEX (0000)
+
+__tolowR:
+
+    dw      HEX (FFFF)
+    dw      HEX (0000)
+    dw      HEX (0001)
+    dw      HEX (0002)
+    dw      HEX (0003)
+    dw      HEX (0004)
+    dw      HEX (0005)
+    dw      HEX (0006)
+    dw      HEX (0007)
+    dw      HEX (0008)
+    dw      HEX (0009)
+    dw      HEX (000A)
+    dw      HEX (000B)
+    dw      HEX (000C)
+    dw      HEX (000D)
+    dw      HEX (000E)
+    dw      HEX (000F)
+    dw      HEX (0010)
+    dw      HEX (0011)
+    dw      HEX (0012)
+    dw      HEX (0013)
+    dw      HEX (0014)
+    dw      HEX (0015)
+    dw      HEX (0016)
+    dw      HEX (0017)
+    dw      HEX (0018)
+    dw      HEX (0019)
+    dw      HEX (001A)
+    dw      HEX (001B)
+    dw      HEX (001C)
+    dw      HEX (001D)
+    dw      HEX (001E)
+    dw      HEX (001F)
+    dw      HEX (0020)
+    dw      HEX (0021)
+    dw      HEX (0022)
+    dw      HEX (0023)
+    dw      HEX (0024)
+    dw      HEX (0025)
+    dw      HEX (0026)
+    dw      HEX (0027)
+    dw      HEX (0028)
+    dw      HEX (0029)
+    dw      HEX (002A)
+    dw      HEX (002B)
+    dw      HEX (002C)
+    dw      HEX (002D)
+    dw      HEX (002E)
+    dw      HEX (002F)
+    dw      HEX (0030)
+    dw      HEX (0031)
+    dw      HEX (0032)
+    dw      HEX (0033)
+    dw      HEX (0034)
+    dw      HEX (0035)
+    dw      HEX (0036)
+    dw      HEX (0037)
+    dw      HEX (0038)
+    dw      HEX (0039)
+    dw      HEX (003A)
+    dw      HEX (003B)
+    dw      HEX (003C)
+    dw      HEX (003D)
+    dw      HEX (003E)
+    dw      HEX (003F)
+    dw      HEX (0040)
+    dw      HEX (0061)
+    dw      HEX (0062)
+    dw      HEX (0063)
+    dw      HEX (0064)
+    dw      HEX (0065)
+    dw      HEX (0066)
+    dw      HEX (0067)
+    dw      HEX (0068)
+    dw      HEX (0069)
+    dw      HEX (006A)
+    dw      HEX (006B)
+    dw      HEX (006C)
+    dw      HEX (006D)
+    dw      HEX (006E)
+    dw      HEX (006F)
+    dw      HEX (0070)
+    dw      HEX (0071)
+    dw      HEX (0072)
+    dw      HEX (0073)
+    dw      HEX (0074)
+    dw      HEX (0075)
+    dw      HEX (0076)
+    dw      HEX (0077)
+    dw      HEX (0078)
+    dw      HEX (0079)
+    dw      HEX (007A)
+    dw      HEX (005B)
+    dw      HEX (005C)
+    dw      HEX (005D)
+    dw      HEX (005E)
+    dw      HEX (005F)
+    dw      HEX (0060)
+    dw      HEX (0061)
+    dw      HEX (0062)
+    dw      HEX (0063)
+    dw      HEX (0064)
+    dw      HEX (0065)
+    dw      HEX (0066)
+    dw      HEX (0067)
+    dw      HEX (0068)
+    dw      HEX (0069)
+    dw      HEX (006A)
+    dw      HEX (006B)
+    dw      HEX (006C)
+    dw      HEX (006D)
+    dw      HEX (006E)
+    dw      HEX (006F)
+    dw      HEX (0070)
+    dw      HEX (0071)
+    dw      HEX (0072)
+    dw      HEX (0073)
+    dw      HEX (0074)
+    dw      HEX (0075)
+    dw      HEX (0076)
+    dw      HEX (0077)
+    dw      HEX (0078)
+    dw      HEX (0079)
+    dw      HEX (007A)
+    dw      HEX (007B)
+    dw      HEX (007C)
+    dw      HEX (007D)
+    dw      HEX (007E)
+    dw      HEX (007F)
+    dw      HEX (0080)
+    dw      HEX (0081)
+    dw      HEX (0082)
+    dw      HEX (0083)
+    dw      HEX (0084)
+    dw      HEX (0085)
+    dw      HEX (0086)
+    dw      HEX (0087)
+    dw      HEX (0088)
+    dw      HEX (0089)
+    dw      HEX (008A)
+    dw      HEX (008B)
+    dw      HEX (008C)
+    dw      HEX (008D)
+    dw      HEX (008E)
+    dw      HEX (008F)
+    dw      HEX (0090)
+    dw      HEX (0091)
+    dw      HEX (0092)
+    dw      HEX (0093)
+    dw      HEX (0094)
+    dw      HEX (0095)
+    dw      HEX (0096)
+    dw      HEX (0097)
+    dw      HEX (0098)
+    dw      HEX (0099)
+    dw      HEX (009A)
+    dw      HEX (009B)
+    dw      HEX (009C)
+    dw      HEX (009D)
+    dw      HEX (009E)
+    dw      HEX (009F)
+    dw      HEX (00A0)
+    dw      HEX (00A1)
+    dw      HEX (00A2)
+    dw      HEX (00A3)
+    dw      HEX (00A4)
+    dw      HEX (00A5)
+    dw      HEX (00A6)
+    dw      HEX (00A7)
+    dw      HEX (00A8)
+    dw      HEX (00A9)
+    dw      HEX (00AA)
+    dw      HEX (00AB)
+    dw      HEX (00AC)
+    dw      HEX (00AD)
+    dw      HEX (00AE)
+    dw      HEX (00AF)
+    dw      HEX (00B0)
+    dw      HEX (00B1)
+    dw      HEX (00B2)
+    dw      HEX (00B3)
+    dw      HEX (00B4)
+    dw      HEX (00B5)
+    dw      HEX (00B6)
+    dw      HEX (00B7)
+    dw      HEX (00B8)
+    dw      HEX (00B9)
+    dw      HEX (00BA)
+    dw      HEX (00BB)
+    dw      HEX (00BC)
+    dw      HEX (00BD)
+    dw      HEX (00BE)
+    dw      HEX (00BF)
+    dw      HEX (00C0)
+    dw      HEX (00C1)
+    dw      HEX (00C2)
+    dw      HEX (00C3)
+    dw      HEX (00C4)
+    dw      HEX (00C5)
+    dw      HEX (00C6)
+    dw      HEX (00C7)
+    dw      HEX (00C8)
+    dw      HEX (00C9)
+    dw      HEX (00CA)
+    dw      HEX (00CB)
+    dw      HEX (00CC)
+    dw      HEX (00CD)
+    dw      HEX (00CE)
+    dw      HEX (00CF)
+    dw      HEX (00D0)
+    dw      HEX (00D1)
+    dw      HEX (00D2)
+    dw      HEX (00D3)
+    dw      HEX (00D4)
+    dw      HEX (00D5)
+    dw      HEX (00D6)
+    dw      HEX (00D7)
+    dw      HEX (00D8)
+    dw      HEX (00D9)
+    dw      HEX (00DA)
+    dw      HEX (00DB)
+    dw      HEX (00DC)
+    dw      HEX (00DD)
+    dw      HEX (00DE)
+    dw      HEX (00DF)
+    dw      HEX (00E0)
+    dw      HEX (00E1)
+    dw      HEX (00E2)
+    dw      HEX (00E3)
+    dw      HEX (00E4)
+    dw      HEX (00E5)
+    dw      HEX (00E6)
+    dw      HEX (00E7)
+    dw      HEX (00E8)
+    dw      HEX (00E9)
+    dw      HEX (00EA)
+    dw      HEX (00EB)
+    dw      HEX (00EC)
+    dw      HEX (00ED)
+    dw      HEX (00EE)
+    dw      HEX (00EF)
+    dw      HEX (00F0)
+    dw      HEX (00F1)
+    dw      HEX (00F2)
+    dw      HEX (00F3)
+    dw      HEX (00F4)
+    dw      HEX (00F5)
+    dw      HEX (00F6)
+    dw      HEX (00F7)
+    dw      HEX (00F8)
+    dw      HEX (00F9)
+    dw      HEX (00FA)
+    dw      HEX (00FB)
+    dw      HEX (00FC)
+    dw      HEX (00FD)
+    dw      HEX (00FE)
+    dw      HEX (00FF)
+
+__toupR:
+
+    dw      HEX (FFFF)
+    dw      HEX (0000)
+    dw      HEX (0001)
+    dw      HEX (0002)
+    dw      HEX (0003)
+    dw      HEX (0004)
+    dw      HEX (0005)
+    dw      HEX (0006)
+    dw      HEX (0007)
+    dw      HEX (0008)
+    dw      HEX (0009)
+    dw      HEX (000A)
+    dw      HEX (000B)
+    dw      HEX (000C)
+    dw      HEX (000D)
+    dw      HEX (000E)
+    dw      HEX (000F)
+    dw      HEX (0010)
+    dw      HEX (0011)
+    dw      HEX (0012)
+    dw      HEX (0013)
+    dw      HEX (0014)
+    dw      HEX (0015)
+    dw      HEX (0016)
+    dw      HEX (0017)
+    dw      HEX (0018)
+    dw      HEX (0019)
+    dw      HEX (001A)
+    dw      HEX (001B)
+    dw      HEX (001C)
+    dw      HEX (001D)
+    dw      HEX (001E)
+    dw      HEX (001F)
+    dw      HEX (0020)
+    dw      HEX (0021)
+    dw      HEX (0022)
+    dw      HEX (0023)
+    dw      HEX (0024)
+    dw      HEX (0025)
+    dw      HEX (0026)
+    dw      HEX (0027)
+    dw      HEX (0028)
+    dw      HEX (0029)
+    dw      HEX (002A)
+    dw      HEX (002B)
+    dw      HEX (002C)
+    dw      HEX (002D)
+    dw      HEX (002E)
+    dw      HEX (002F)
+    dw      HEX (0030)
+    dw      HEX (0031)
+    dw      HEX (0032)
+    dw      HEX (0033)
+    dw      HEX (0034)
+    dw      HEX (0035)
+    dw      HEX (0036)
+    dw      HEX (0037)
+    dw      HEX (0038)
+    dw      HEX (0039)
+    dw      HEX (003A)
+    dw      HEX (003B)
+    dw      HEX (003C)
+    dw      HEX (003D)
+    dw      HEX (003E)
+    dw      HEX (003F)
+    dw      HEX (0040)
+    dw      HEX (0041)
+    dw      HEX (0042)
+    dw      HEX (0043)
+    dw      HEX (0044)
+    dw      HEX (0045)
+    dw      HEX (0046)
+    dw      HEX (0047)
+    dw      HEX (0048)
+    dw      HEX (0049)
+    dw      HEX (004A)
+    dw      HEX (004B)
+    dw      HEX (004C)
+    dw      HEX (004D)
+    dw      HEX (004E)
+    dw      HEX (004F)
+    dw      HEX (0050)
+    dw      HEX (0051)
+    dw      HEX (0052)
+    dw      HEX (0053)
+    dw      HEX (0054)
+    dw      HEX (0055)
+    dw      HEX (0056)
+    dw      HEX (0057)
+    dw      HEX (0058)
+    dw      HEX (0059)
+    dw      HEX (005A)
+    dw      HEX (005B)
+    dw      HEX (005C)
+    dw      HEX (005D)
+    dw      HEX (005E)
+    dw      HEX (005F)
+    dw      HEX (0060)
+    dw      HEX (0041)
+    dw      HEX (0042)
+    dw      HEX (0043)
+    dw      HEX (0044)
+    dw      HEX (0045)
+    dw      HEX (0046)
+    dw      HEX (0047)
+    dw      HEX (0048)
+    dw      HEX (0049)
+    dw      HEX (004A)
+    dw      HEX (004B)
+    dw      HEX (004C)
+    dw      HEX (004D)
+    dw      HEX (004E)
+    dw      HEX (004F)
+    dw      HEX (0050)
+    dw      HEX (0051)
+    dw      HEX (0052)
+    dw      HEX (0053)
+    dw      HEX (0054)
+    dw      HEX (0055)
+    dw      HEX (0056)
+    dw      HEX (0057)
+    dw      HEX (0058)
+    dw      HEX (0059)
+    dw      HEX (005A)
+    dw      HEX (007B)
+    dw      HEX (007C)
+    dw      HEX (007D)
+    dw      HEX (007E)
+    dw      HEX (007F)
+    dw      HEX (0080)
+    dw      HEX (0081)
+    dw      HEX (0082)
+    dw      HEX (0083)
+    dw      HEX (0084)
+    dw      HEX (0085)
+    dw      HEX (0086)
+    dw      HEX (0087)
+    dw      HEX (0088)
+    dw      HEX (0089)
+    dw      HEX (008A)
+    dw      HEX (008B)
+    dw      HEX (008C)
+    dw      HEX (008D)
+    dw      HEX (008E)
+    dw      HEX (008F)
+    dw      HEX (0090)
+    dw      HEX (0091)
+    dw      HEX (0092)
+    dw      HEX (0093)
+    dw      HEX (0094)
+    dw      HEX (0095)
+    dw      HEX (0096)
+    dw      HEX (0097)
+    dw      HEX (0098)
+    dw      HEX (0099)
+    dw      HEX (009A)
+    dw      HEX (009B)
+    dw      HEX (009C)
+    dw      HEX (009D)
+    dw      HEX (009E)
+    dw      HEX (009F)
+    dw      HEX (00A0)
+    dw      HEX (00A1)
+    dw      HEX (00A2)
+    dw      HEX (00A3)
+    dw      HEX (00A4)
+    dw      HEX (00A5)
+    dw      HEX (00A6)
+    dw      HEX (00A7)
+    dw      HEX (00A8)
+    dw      HEX (00A9)
+    dw      HEX (00AA)
+    dw      HEX (00AB)
+    dw      HEX (00AC)
+    dw      HEX (00AD)
+    dw      HEX (00AE)
+    dw      HEX (00AF)
+    dw      HEX (00B0)
+    dw      HEX (00B1)
+    dw      HEX (00B2)
+    dw      HEX (00B3)
+    dw      HEX (00B4)
+    dw      HEX (00B5)
+    dw      HEX (00B6)
+    dw      HEX (00B7)
+    dw      HEX (00B8)
+    dw      HEX (00B9)
+    dw      HEX (00BA)
+    dw      HEX (00BB)
+    dw      HEX (00BC)
+    dw      HEX (00BD)
+    dw      HEX (00BE)
+    dw      HEX (00BF)
+    dw      HEX (00C0)
+    dw      HEX (00C1)
+    dw      HEX (00C2)
+    dw      HEX (00C3)
+    dw      HEX (00C4)
+    dw      HEX (00C5)
+    dw      HEX (00C6)
+    dw      HEX (00C7)
+    dw      HEX (00C8)
+    dw      HEX (00C9)
+    dw      HEX (00CA)
+    dw      HEX (00CB)
+    dw      HEX (00CC)
+    dw      HEX (00CD)
+    dw      HEX (00CE)
+    dw      HEX (00CF)
+    dw      HEX (00D0)
+    dw      HEX (00D1)
+    dw      HEX (00D2)
+    dw      HEX (00D3)
+    dw      HEX (00D4)
+    dw      HEX (00D5)
+    dw      HEX (00D6)
+    dw      HEX (00D7)
+    dw      HEX (00D8)
+    dw      HEX (00D9)
+    dw      HEX (00DA)
+    dw      HEX (00DB)
+    dw      HEX (00DC)
+    dw      HEX (00DD)
+    dw      HEX (00DE)
+    dw      HEX (00DF)
+    dw      HEX (00E0)
+    dw      HEX (00E1)
+    dw      HEX (00E2)
+    dw      HEX (00E3)
+    dw      HEX (00E4)
+    dw      HEX (00E5)
+    dw      HEX (00E6)
+    dw      HEX (00E7)
+    dw      HEX (00E8)
+    dw      HEX (00E9)
+    dw      HEX (00EA)
+    dw      HEX (00EB)
+    dw      HEX (00EC)
+    dw      HEX (00ED)
+    dw      HEX (00EE)
+    dw      HEX (00EF)
+    dw      HEX (00F0)
+    dw      HEX (00F1)
+    dw      HEX (00F2)
+    dw      HEX (00F3)
+    dw      HEX (00F4)
+    dw      HEX (00F5)
+    dw      HEX (00F6)
+    dw      HEX (00F7)
+    dw      HEX (00F8)
+    dw      HEX (00F9)
+    dw      HEX (00FA)
+    dw      HEX (00FB)
+    dw      HEX (00FC)
+    dw      HEX (00FD)
+    dw      HEX (00FE)
+    dw      HEX (00FF)
diff --git a/src/lib/crt/include/stdio.inc b/src/lib/crt/include/stdio.inc
new file mode 100644 (file)
index 0000000..165b10a
--- /dev/null
@@ -0,0 +1,13 @@
+;******************************************************************************
+; @file             stdio.inc
+;******************************************************************************
+%ifndef     _STDIO_INC
+%define     _STDIO_INC
+
+%define     __SRD                       0x0004
+%define     __SWR                       0x0008
+%define     __SRW                       0x0010
+%define     __SEOF                      0x0020
+%define     __SAPP                      0x0100
+
+%endif      ; _STDIO_INC
diff --git a/src/lib/crt/include/sys/fcntl.inc b/src/lib/crt/include/sys/fcntl.inc
new file mode 100644 (file)
index 0000000..0ec7ed2
--- /dev/null
@@ -0,0 +1,16 @@
+;******************************************************************************
+; @file             fcntl.inc
+;******************************************************************************
+%ifndef     _FCNTL_INC
+%define     _FCNTL_INC
+
+%define     O_CREAT                     0x0040
+%define     O_TRUNC                     0x0200
+%define     O_APPEND                    0x0400
+%define     O_ACCMODE                   (O_RDONLY | O_WRONLY | O_RDWR)
+
+%define     O_RDONLY                    (0)
+%define     O_WRONLY                    (1)
+%define     O_RDWR                      (2)
+
+%endif      ; _FCNTL_INC
diff --git a/src/lib/crt/stdio/fclose.asm b/src/lib/crt/stdio/fclose.asm
new file mode 100644 (file)
index 0000000..27bcbed
--- /dev/null
@@ -0,0 +1,90 @@
+;******************************************************************************
+; @file             fclose.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fclose
+;******************************************************************************
+global      _fclose
+_fclose:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actaully have some value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _fclose.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    xor     si,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es:[si]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=3E to close the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (3E)
+    int     HEX (21)
+    jc      _fclose.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Free our pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    word ptr [bp + 4]
+    
+    call    _free
+    add     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
+
+_fclose.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdio/feof.asm b/src/lib/crt/stdio/feof.asm
new file mode 100644 (file)
index 0000000..b67f574
--- /dev/null
@@ -0,0 +1,97 @@
+;******************************************************************************
+; @file             feof.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _feof
+;******************************************************************************
+global      _feof
+_feof:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actaully have some value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _feof.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set up the extra segment and si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    xor     si,     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the flags from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     es:[si + 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached EOF?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     __SEOF
+    jz      _feof.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return 1 to indicate that we reached EOF.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     1
+
+_feof.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
+
+_feof.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     es
+    pop     bx
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdio/fgetc.asm b/src/lib/crt/stdio/fgetc.asm
new file mode 100644 (file)
index 0000000..a0eb61e
--- /dev/null
@@ -0,0 +1,144 @@
+;******************************************************************************
+; @file             fgetc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _fgetc
+;******************************************************************************
+global      _fgetc
+_fgetc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have actually pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      _fgetc.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    mov     cx,     es:[di + 2]
+    
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached the end of the file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    cx,     __SEOF
+    jnz     _fgetc.eof
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll read 1 byte.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     1
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the dx register with the address of the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     offset _tempbuf
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read # no of bytes into the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (3F)
+    int     HEX (21)
+    jc      _fgetc.error
+    
+    and     ax,     ax
+    jnz     _fgetc.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add an EOF marker to the flags,
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    or      word ptr es:[di + 2],       __SEOF
+    pop     di
+    pop     es
+    
+    mov     byte ptr cs:[_tempbuf],    0
+
+_fgetc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the character that was read and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_tempbuf]
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fgetc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_tempbuf:                       db      HEX (00)
diff --git a/src/lib/crt/stdio/flags.asm b/src/lib/crt/stdio/flags.asm
new file mode 100644 (file)
index 0000000..64efd06
--- /dev/null
@@ -0,0 +1,155 @@
+;******************************************************************************
+; @file             flags.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <sys/fcntl.inc>
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _sflags
+;******************************************************************************
+global      _sflags
+_sflags:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    
+    mov     si,     word ptr [bp + 4]
+    lodsb
+    
+    cmp     al,     'r'
+    jne     _sflags.not_read
+    
+    mov     bx,     __SRD
+    mov     cx,     O_RDONLY
+    xor     dx,     dx
+    
+    jmp     _sflags.loop
+
+_sflags.not_read:
+
+    cmp     al,     'w'
+    jne     _sflags.not_write
+    
+    mov     bx,     __SWR
+    mov     cx,     O_WRONLY
+    mov     dx,     O_CREAT | O_TRUNC
+    
+    jmp     _sflags.loop
+
+_sflags.not_write:
+
+    cmp     al,     'a'
+    jne     _sflags.not_append
+    
+    mov     bx,     __SWR | __SAPP
+    mov     cx,     O_WRONLY
+    mov     dx,     O_CREAT | O_APPEND
+    
+    jmp     _sflags.loop
+
+_sflags.not_append:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out ax and set the carry flag to indicate an error.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_sflags.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _sflags.done
+    
+    cmp     al,     '+'
+    jne     _sflags.next
+    
+    mov     di,     __SRD | __SWR
+    not     di
+    
+    and     bx,     di
+    or      bx,     __SRW
+    
+    mov     di,     O_ACCMODE
+    not     di
+    
+    and     cx,     di
+    or      cx,     O_RDWR
+
+_sflags.next:
+
+    jmp     short   _sflags.loop
+
+_sflags.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; The stack should contain an address for the flags at offset 6
+    ;; so store it in the di register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     word ptr [bp + 6]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in the cx register into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Or the value with the value stored in the dx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    or      si,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the new value in the address that di points to.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     [di],       si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the return to the value stored in bx and clear the carry flag to
+    ;; indicate success.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdio/fopen.asm b/src/lib/crt/stdio/fopen.asm
new file mode 100644 (file)
index 0000000..b4ad7e9
--- /dev/null
@@ -0,0 +1,313 @@
+;******************************************************************************
+; @file             fopen.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <sys/fcntl.inc>
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _fopen
+;******************************************************************************
+global      _fopen
+_fopen:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    es
+    push    si
+    push    di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We want to extract the flags into our _oflags value so push
+    ;; the address of it to the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     offset _oflags
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Offset +6 on the stack should contain the mode string (i.e. r+) to use
+    ;; when opening the file so get the value and re-push that on the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 6]
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert our mode string into an integer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _sflags
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean-up the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If ax is zero then the flag string was invalid.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     ax
+    jz      _fopen.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the return value into the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set ax to the value of the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     [_oflags]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we need to create the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    ax,     O_CREAT
+    jnz     _fopen.co
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value to remove O_CREAT, O_TRUNC and O_APPEND.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     O_ACCMODE
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=3D to open the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (3D)
+    int     HEX (21)
+    jc      _fopen.error
+
+_fopen.success:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the file handle in ax.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Allocate some memory for a pointer (i.e. FILE *).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     16
+    xor     dx,     dx
+    
+    push    ax
+    push    dx
+    
+    call    _malloc
+    add     sp,     4
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure the malloc didn't fail.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     ax
+    jz      _fopen.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll use es:di to store the values.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     ax
+    xor     di,     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear out the memory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    push    cx
+    
+    mov     cx,     16
+    rep     stosb
+    
+    pop     cx
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the file handle.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Store the flags.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     si
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We're not EOF yet.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stosw
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the value in the extra segment into ax.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     es
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fopen.co:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Are we appending the file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    ax,     O_APPEND
+    jnz     _fopen.append
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value to remove O_CREAT, O_TRUNC and O_APPEND.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     O_ACCMODE
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First try to open the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (3D)
+    int     HEX (21)
+    jnc     _fopen.success
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make the flags read-write.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     __SRD | __SWR
+    not     di
+    
+    and     si,     di
+    or      si,     __SRW
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Create the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (3C)
+    mov     cx,     HEX (20)
+    int     HEX (21)
+    jc      _fopen.error
+    
+    jmp     _fopen.success
+
+_fopen.append:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; And the value to remove O_CREAT, O_TRUNC and O_APPEND.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     ax,     O_ACCMODE
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First try to open the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (3D)
+    int     HEX (21)
+    jnc     _fopen.move
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make the flags read-write.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     __SRD | __SWR
+    not     di
+    
+    and     si,     di
+    or      si,     __SRW
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Create the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (3C)
+    mov     cx,     HEX (20)
+    int     HEX (21)
+    jc      _fopen.error
+
+_fopen.move:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Copy the file handle into the bx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We want to move zero bytes from the end.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+    xor     dx,     dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the file pointer to the end of the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (4202)
+    int     HEX (21)
+    jc      _fopen.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Reset ax back to the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to our success code.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _fopen.success
+
+_fopen.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     es
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_oflags:                        dw      HEX (0000)
diff --git a/src/lib/crt/stdio/fread.asm b/src/lib/crt/stdio/fread.asm
new file mode 100644 (file)
index 0000000..4e60c45
--- /dev/null
@@ -0,0 +1,214 @@
+;******************************************************************************
+; @file             fread.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Includes.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    <stdio.inc>
+
+;******************************************************************************
+; @function         _fread
+;******************************************************************************
+global      _fread
+_fread:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the reserved stack value.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     word ptr [bp - 2],      0
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the buffer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have actually buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;and     si,     si
+    ;jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 10]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Calculate the amount of bytes to read.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    mul     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the number of bytes are zero then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     cx,     cx
+    jz      _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    mov     dx,     es:[di + 2]
+    
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Have we reached the end of the file?
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    test    dx,     __SEOF
+    jnz     _fread.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Move the number of bytes into the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Initialize the dx register with the address of the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Read # no of bytes into the buffer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (3F)
+    int     HEX (21)
+    jc      _fread.error
+    
+    and     ax,     ax
+    jnz     _fread.read_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add an EOF marker to the flags,
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    or      word ptr es:[di + 2],       __SEOF
+    pop     di
+    pop     es
+    
+    jmp     short   _fread.zero
+
+_fread.read_ok:
+
+    cmp     cx,     ax
+    je      _fread.size_ok
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Add an EOF marker to the flags,
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    or      word ptr es:[di + 2],       __SEOF
+    pop     di
+    pop     es
+
+_fread.size_ok:
+
+    cmp     word ptr [bp + 6],      0
+    je      _fread.zero
+    
+    xor     dx,     dx
+    
+    mov     cx,     word ptr [bp + 6]
+    div     cx
+    
+    mov     word ptr [bp - 2],      ax
+    jmp     _fread.done
+
+_fread.zero:
+
+    mov     word ptr [bp - 2],      0
+
+_fread.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp - 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fread.error:
+
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     2
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdio/fseek.asm b/src/lib/crt/stdio/fseek.asm
new file mode 100644 (file)
index 0000000..6b45a0b
--- /dev/null
@@ -0,0 +1,114 @@
+;******************************************************************************
+; @file             fseek.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _fseek
+;******************************************************************************
+global      _fseek
+_fseek:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the seek type off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 10]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the seek value off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     dx,     word ptr [bp + 8]
+    mov     cx,     word ptr [bp + 6]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      _fseek.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Seek the file.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ah,     HEX (42)
+    int     HEX (21)
+    jc      _fseek.error
+
+_fseek.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_fseek.error:
+
+    mov     ax,     -1
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdio/ftell.asm b/src/lib/crt/stdio/ftell.asm
new file mode 100644 (file)
index 0000000..f50a7c5
--- /dev/null
@@ -0,0 +1,97 @@
+;******************************************************************************
+; @file             ftell.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _ftell
+;******************************************************************************
+global      _ftell
+_ftell:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the pointer off the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we actually have a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     si,     si
+    jz      _ftell.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get our file handle from the pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    es
+    push    di
+    
+    mov     es,     si
+    xor     di,     di
+    
+    mov     bx,     es:[di + 0]
+    pop     di
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Seek the file with 0.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     HEX (4201)
+    xor     cx,     cx
+    xor     dx,     dx
+    int     HEX (21)
+    jc      _ftell.error
+
+_ftell.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
+
+_ftell.error:
+
+    mov     ax,     -1
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the base pointer and return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdlib/free.asm b/src/lib/crt/stdlib/free.asm
new file mode 100644 (file)
index 0000000..d165740
--- /dev/null
@@ -0,0 +1,37 @@
+;******************************************************************************
+; @file             free.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _free
+;******************************************************************************
+global      _free
+_free:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=49 to free the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     word ptr [bp + 4]
+    
+    mov     ah,     HEX (49)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     ax
+    pop     bp
+    ret
diff --git a/src/lib/crt/stdlib/malloc.asm b/src/lib/crt/stdlib/malloc.asm
new file mode 100644 (file)
index 0000000..bebd0ec
--- /dev/null
@@ -0,0 +1,90 @@
+;******************************************************************************
+; @file             malloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _malloc
+;******************************************************************************
+global      _malloc
+_malloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    dx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 6]
+    mov     dx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the size to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _malloc.ok
+
+_malloc.inc:
+
+    inc     ax
+    jz      _malloc.error
+
+_malloc.ok:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=48 to allocate the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bx,     ax
+    
+    mov     ah,     HEX (48)
+    int     HEX (21)
+    jc      _malloc.error
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_malloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/lib/crt/stdlib/realloc.asm b/src/lib/crt/stdlib/realloc.asm
new file mode 100644 (file)
index 0000000..2e43b97
--- /dev/null
@@ -0,0 +1,233 @@
+;******************************************************************************
+; @file             realloc.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _realloc
+;******************************************************************************
+global      _realloc
+_realloc:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    cx
+    push    si
+    push    di
+    push    dx
+    push    es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the size (in bytes) from the stack as well as the pointer to
+    ;; re-allocate.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     word ptr [bp + 8]
+    mov     dx,     word ptr [bp + 6]
+    mov     bx,     word ptr [bp + 4]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Make sure we have valid memory as a pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    and     bx,     bx
+    jz      _realloc.calc
+    
+    mov     di,     bx
+    dec     di
+    mov     es,     di
+    
+    xor     di,     di
+    
+    cmp     byte ptr es:[di],       'M'
+    jne     _realloc.error
+    
+    cmp     byte ptr es:[di + 1],   'C'
+    jne     _realloc.error
+    
+    cmp     byte ptr es:[di + 2],   'B'
+    jne     _realloc.error
+
+_realloc.calc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Convert the size to paragraphs.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cx,     16
+    div     cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If dx is non-zero then try to increase the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     0
+    je      _realloc.ok
+
+_realloc.inc:
+
+    inc     ax
+    jz      _realloc.error
+
+_realloc.ok:
+
+    mov     si,     ax
+    
+    and     bx,     bx
+    jz      _realloc.alloc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; First. lets try and resize the memory block.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    es
+    
+    mov     es,     bx
+    mov     bx,     si
+    
+    mov     ah,     HEX (4A)
+    int     HEX (21)
+    pop     es
+    pop     bx
+    jnc     _realloc.done
+
+_realloc.alloc:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Call int 21h/ah=48 to allocate the blocks.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    mov     bx,     si
+    
+    mov     ah,     HEX (48)
+    int     HEX (21)
+    pop     bx
+    jc      _realloc.error
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Only copy existing data if there was an original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     di,     bx
+    
+    and     di,     di
+    jz      _realloc.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers that copy will clobber.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    push    ds
+    
+    mov     di,     bx
+    mov     ds,     di
+    
+    dec     di
+    
+    mov     es,     di
+    xor     di,     di
+    
+    mov     cx,     word ptr es:[di + 3]
+    mov     es,     ax
+    
+    cmp     cx,     bx
+    jb      _realloc.copy
+    
+    mov     cx,     bx
+
+_realloc.copy:
+
+    xor     si,     si
+    xor     di,     di
+    
+    push    cx
+    
+    mov     cx,     16
+    rep     movsb
+    
+    pop     cx
+    
+    mov     si,     es
+    inc     si
+    mov     es,     si
+    
+    mov     di,     ds
+    inc     di
+    mov     ds,     di
+    
+    loop    _realloc.copy
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers that copy clobbered.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     si
+
+_realloc.free:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If we reached this point then free the original pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     es,     bx
+    
+    mov     ah,     HEX (49)
+    int     HEX (21)
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the new pointer;
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ax
+
+_realloc.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    clc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clear the carry flag and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
+
+_realloc.error:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Zero out the ax register and set the carry flag.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     ax,     ax
+    stc
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     es
+    pop     dx
+    pop     di
+    pop     si
+    pop     cx
+    pop     bx
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
diff --git a/src/lib/crt/string/memmove.asm b/src/lib/crt/string/memmove.asm
new file mode 100644 (file)
index 0000000..ec8cb39
--- /dev/null
@@ -0,0 +1,91 @@
+;******************************************************************************
+; @file             memmove.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _memmove
+;******************************************************************************
+global      _memmove
+_memmove:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    si
+    push    di
+    push    bx
+    push    cx
+    
+    mov     di,     word ptr [bp + 4]
+    mov     si,     word ptr [bp + 6]
+    mov     cx,     word ptr [bp + 8]
+
+.L3:
+
+    cmp     di,     si
+    ja      .L2
+
+.L4:
+
+    and     cx,     cx
+    jz      .L1
+    
+    movsb
+    dec     cx
+    
+    jmp     .L4
+    
+    jmp     .L1
+
+.L2:
+
+    and     cx,     cx
+    jz      .L1
+    
+    dec     cx
+
+.L6:
+
+    and     cx,     cx
+    jz      .L5
+    
+    mov     bx,     si
+    add     bx,     cx
+    
+    mov     al,     [si]
+    
+    mov     bx,     di
+    add     bx,     cx
+    
+    mov     es:[di],    al
+    
+    dec     cx
+    jmp     .L6
+
+.L5:
+
+    mov     bx,     si
+    add     bx,     cx
+    
+    mov     al,     [si]
+    
+    mov     bx,     di
+    add     bx,     cx
+    
+    mov     es:[di],    al
+
+.L1:
+
+    pop     cx
+    pop     bx
+    pop     di
+    pop     si
+    
+    mov     ax,     word ptr [bp + 4]
+    clc
+    
+    pop     bp
+    ret
diff --git a/src/lib/crt/string/strchr.asm b/src/lib/crt/string/strchr.asm
new file mode 100644 (file)
index 0000000..b313bb6
--- /dev/null
@@ -0,0 +1,52 @@
+;******************************************************************************
+; @file             strchr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strchr
+;******************************************************************************
+global      _strchr
+_strchr:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    si
+    push    bx
+    
+    mov     bx,     word ptr [bp + 6]
+    mov     si,     word ptr [bp + 4]
+
+_strchr.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strchr.done
+    
+    cmp     al,     bl
+    je      _strchr.found
+    
+    jmp     short   _strchr.loop
+
+_strchr.found:
+
+    mov     ax,     si
+    dec     ax
+    
+    pop     bx
+    pop     si
+    pop     bp
+    ret
+
+_strchr.done:
+
+    xor     ax,     ax
+    
+    pop     bx
+    pop     si
+    pop     bp
+    ret
diff --git a/src/lib/crt/string/strcmp.asm b/src/lib/crt/string/strcmp.asm
new file mode 100644 (file)
index 0000000..946f5ee
--- /dev/null
@@ -0,0 +1,99 @@
+;******************************************************************************
+; @file             strcmp.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strcmp
+;******************************************************************************
+global      _strcmp
+_strcmp:
+
+    push    bp
+    mov     bp,     sp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    bx
+    push    si
+    push    di
+    
+    mov     si,     word ptr [bp + 6]
+    mov     di,     word ptr [bp + 4]
+
+_strcmp.loop:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we've reached the end of a string.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     byte ptr [si],      0
+    je      _strcmp.check
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get one character from both si and di.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     bh,     [si]
+    mov     bl,     [di]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If bh (byte from si) is less than bl (byte from di) then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bh,     bl
+    jb      _strcmp.less
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If bh (byte from si) is greater than bl (byte from di) then we're done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     bh,     bl
+    ja      _strcmp.more
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Advance si and di to the next character
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    inc     si
+    inc     di
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Run the check again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     short   _strcmp.loop
+
+_strcmp.less:
+
+    mov     ax,     -1
+    stc
+    
+    jmp     short   _strcmp.done
+
+_strcmp.more:
+
+    mov     ax,     1
+    stc
+    
+    jmp     short   _strcmp.done
+
+_strcmp.check:
+
+    xor     ax,     ax
+    clc
+    
+    cmp     byte ptr [di],      0
+    je      _strcmp.done
+    
+    mov     ax,     -1
+    stc
+
+_strcmp.done:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers and return.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     di
+    pop     si
+    pop     bx
+    
+    pop     bp
+    ret
diff --git a/src/lib/crt/string/strcpy.asm b/src/lib/crt/string/strcpy.asm
new file mode 100644 (file)
index 0000000..6e93188
--- /dev/null
@@ -0,0 +1,42 @@
+;******************************************************************************
+; @file             strcpy.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strcpy
+;******************************************************************************
+global      _strcpy
+_strcpy:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    cx
+    push    si
+    push    di
+    
+    mov     si,     word ptr [bp + 6]
+    mov     di,     word ptr [bp + 4]
+
+_strcpy.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strcpy.done
+    
+    stosb
+    jmp     short   _strcpy.loop
+
+_strcpy.done:
+
+    mov     ax,     di
+    
+    pop     di
+    pop     si
+    pop     cx
+    pop     bp
+    ret
diff --git a/src/lib/crt/string/strlen.asm b/src/lib/crt/string/strlen.asm
new file mode 100644 (file)
index 0000000..53159bd
--- /dev/null
@@ -0,0 +1,47 @@
+;******************************************************************************
+; @file             strlen.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strlen
+;******************************************************************************
+global      _strlen
+_strlen:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     2
+    
+    push    cx
+    push    si
+    push    di
+    
+    mov     si,     word ptr [bp + 4]
+    mov     word ptr [bp - 2],      0
+
+_strlen.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strlen.done
+    
+    inc     word ptr [bp - 2]
+    jmp     short   _strlen.loop
+
+_strlen.done:
+
+    mov     ax,     word ptr [bp - 2]
+    
+    pop     di
+    pop     si
+    pop     cx
+    
+    add     sp,     2
+    pop     bp
+    
+    ret
diff --git a/src/lib/crt/string/strrchr.asm b/src/lib/crt/string/strrchr.asm
new file mode 100644 (file)
index 0000000..f45c4c1
--- /dev/null
@@ -0,0 +1,49 @@
+;******************************************************************************
+; @file             strrchr.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _strrchr
+;******************************************************************************
+global      _strrchr
+_strrchr:
+
+    push    bp
+    mov     bp,     sp
+    
+    push    si
+    push    bx
+    push    di
+    
+    mov     bx,     word ptr [bp + 6]
+    mov     si,     word ptr [bp + 4]
+    
+    xor     di,     di
+
+_strrchr.loop:
+
+    lodsb
+    
+    or      al,     al
+    jz      _strrchr.done
+    
+    cmp     al,     bl
+    jne     _strrchr.loop
+    
+    mov     di,     si
+    dec     di
+    
+    jmp     short   _strrchr.loop
+
+_strrchr.done:
+
+    mov     ax,     di
+    
+    pop     di
+    pop     bx
+    pop     si
+    pop     bp
+    ret
diff --git a/src/lib/crt/udivmodsi4.asm b/src/lib/crt/udivmodsi4.asm
new file mode 100644 (file)
index 0000000..7a99176
--- /dev/null
@@ -0,0 +1,153 @@
+;******************************************************************************
+; @file             _udivmodsi4.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _udivmodsi4
+;******************************************************************************
+global      _udivmodsi4
+_udivmodsi4:
+
+    push    si
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     12
+    
+    mov     word ptr [bp - 4],      1
+    mov     word ptr [bp - 2],      0
+    mov     word ptr [bp - 8],      0
+    mov     word ptr [bp - 6],      0
+    
+    jmp     .L2
+
+.L6:
+
+    shl     word ptr [bp + 10]
+    rcl     word ptr [bp + 12]
+    shl     word ptr [bp - 4]
+    rcl     word ptr [bp - 2]
+
+.L2:
+
+    mov     ax,     word ptr [bp + 8]
+    cmp     ax,     word ptr [bp + 12]
+    ja      .L14
+    
+    mov     ax,     word ptr [bp + 8]
+    cmp     ax,     word ptr [bp + 12]
+    jne     .L8
+    
+    mov     ax,     word ptr [bp + 6]
+    cmp     ax,     word ptr [bp + 10]
+    jbe     .L3
+
+.L14:
+
+    mov     dx,     word ptr [bp - 4]
+    mov     ax,     word ptr [bp - 2]
+    
+    or      ax,     dx
+    cmp     ax,     1
+    
+    test    ax,     ax
+    je      .L8
+    
+    mov     ax,     word ptr [bp + 10]
+    mov     dx,     word ptr [bp + 12]
+    
+    test    dx,     dx
+    jge     .L6
+
+.L3:
+
+    jmp     .L8
+
+.L11:
+
+    mov     ax,     word ptr [bp + 12]
+    
+    cmp     ax,     word ptr [bp + 8]
+    ja      .L9
+    
+    mov     ax,     word ptr [bp + 12]
+    
+    cmp     ax,     word ptr [bp + 8]
+    jne     .L15
+    
+    mov     ax,     word ptr [bp + 10]
+    
+    cmp     ax,     word ptr [bp + 6]
+    ja      .L9
+
+.L15:
+
+    mov     bx,     word ptr [bp + 6]
+    mov     si,     word ptr [bp + 8]
+    
+    mov     ax,     word ptr [bp + 10]
+    mov     dx,     word ptr [bp + 12]
+    
+    mov     cx,     bx
+    sub     cx,     ax
+    mov     word ptr [bp - 12],     cx
+    
+    mov     cx,     si
+    sbb     cx,     dx
+    mov     word ptr [bp - 10],     cx
+    
+    mov     ax,     word ptr [bp - 12]
+    mov     word ptr [bp + 6],      ax
+    mov     ax,     word ptr [bp - 10]
+    mov     word ptr [bp + 8],      ax
+    
+    mov     dx,     word ptr [bp - 8]
+    mov     ax,     word ptr [bp - 4]
+    or      ax,     dx
+    mov     word ptr [bp - 8],      ax
+    
+    mov     dx,     word ptr [bp - 6]
+    mov     ax,     word ptr [bp - 2]
+    or      ax,     dx
+    mov     word ptr [bp - 6],      ax
+
+.L9:
+
+    shr     word ptr [bp - 2]
+    rcr     word ptr [bp - 4]
+    
+    shr     word ptr [bp + 12]
+    rcr     word ptr [bp + 10]
+
+.L8:
+
+    mov     dx,     word ptr [bp - 4]
+    mov     ax,     word ptr [bp - 2]
+    or      ax,     dx
+    cmp     ax,     1
+    
+    test    ax,     ax
+    jne     .L11
+    
+    cmp     word ptr [bp + 14],     0
+    je      .L12
+    
+    mov     ax,     word ptr [bp + 6]
+    mov     dx,     word ptr [bp + 8]
+    
+    jmp     .L13
+
+.L12:
+
+    mov     ax,     word ptr [bp - 8]
+    mov     dx,     word ptr [bp - 6]
+
+.L13:
+
+    add     sp,     12
+    pop     bp
+    pop     si
+    ret
diff --git a/src/utils/Makefile.unix b/src/utils/Makefile.unix
new file mode 100644 (file)
index 0000000..1d7c699
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  dosfstools parted binutils
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for d in $(TARGETS); do \
+         if [ ! -d "$(OBJDIR)/$$d" ]; then mkdir -p "$(OBJDIR)/$$d"; fi; \
+         $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" all; \
+       done
+
+clean:
+       for d in $(TARGETS); do \
+         if [ -d "$(OBJDIR)/$$d" ]; then \
+           $(MAKE) -C "$(OBJDIR)/$$d" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)/$$d" SRCDIR="$(SRCDIR)/$$d" clean; \
+         fi; \
+       done
diff --git a/src/utils/Makefile.w32 b/src/utils/Makefile.w32
new file mode 100644 (file)
index 0000000..bedc723
--- /dev/null
@@ -0,0 +1,20 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  dosfstools parted binutils
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%d in ($(TARGETS)) do ( \
+         ( if not exist "$(OBJDIR)/%%d" ( mkdir "$(OBJDIR)/%%d" ) ) & \
+         $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" all \
+       )
+
+clean:
+       for %%d in ($(TARGETS)) do ( \
+         if exist "$(OBJDIR)/%%d" ( \
+           $(MAKE) -C "$(OBJDIR)/%%d" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)/%%d" SRCDIR="$(SRCDIR)/%%d" clean \
+         ) \
+       )
diff --git a/src/utils/binutils/Makefile.unix b/src/utils/binutils/Makefile.unix
new file mode 100644 (file)
index 0000000..31b073a
--- /dev/null
@@ -0,0 +1,17 @@
+#******************************************************************************
+# @file             Makefile.unix
+#******************************************************************************
+TARGETS             :=  ar as ld
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for d in $(TARGETS); do \
+         $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)/$$d" all; \
+       done
+
+clean:
+       for d in $(TARGETS); do \
+         $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/$$d/Makefile.unix" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)/$$d" clean; \
+       done
diff --git a/src/utils/binutils/Makefile.w32 b/src/utils/binutils/Makefile.w32
new file mode 100644 (file)
index 0000000..3022f72
--- /dev/null
@@ -0,0 +1,17 @@
+#******************************************************************************
+# @file             Makefile.w32
+#******************************************************************************
+TARGETS             :=  ar as ld
+
+OBJDIR              ?=  $(CURDIR)
+SRCDIR              ?=  $(CURDIR)
+
+all:
+       for %%d in ($(TARGETS)) do ( \
+         $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)/%%d" all \
+       )
+
+clean:
+       for %%d in ($(TARGETS)) do ( \
+         $(MAKE) -C "$(OBJDIR)" -f "$(SRCDIR)/%%d/Makefile.w32" OBJDIR="$(OBJDIR)" SRCDIR="$(SRCDIR)/%%d" clean \
+       )
diff --git a/src/utils/binutils/ar b/src/utils/binutils/ar
new file mode 160000 (submodule)
index 0000000..d7ae5cc
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d7ae5ccfda2892d7804ab86039a740547c089158
diff --git a/src/utils/binutils/as b/src/utils/binutils/as
new file mode 160000 (submodule)
index 0000000..1c5f2de
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 1c5f2de0ea49b930fc16bbf187b1adb64cd01832
diff --git a/src/utils/binutils/ld b/src/utils/binutils/ld
new file mode 160000 (submodule)
index 0000000..ee1bb0f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit ee1bb0fe4d5e457480ff4ab46fd1f9cf40a1cfb2
diff --git a/src/utils/dosfstools b/src/utils/dosfstools
new file mode 160000 (submodule)
index 0000000..2b218a0
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 2b218a0bd719edc90f0e6168b8c55c909ee67703
diff --git a/src/utils/parted b/src/utils/parted
new file mode 160000 (submodule)
index 0000000..d0bd265
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit d0bd265427872bba3161c4d1b4a73b8058d0cb9f