From d7d39a77ad3dc1701972069a7ea201ee38b47a93 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Wed, 31 Jul 2024 16:05:26 +0100 Subject: [PATCH] Initial commit --- .gitmodules | 15 + Makefile.unix | 19 + Makefile.w32 | 19 + build/chimaera.img | Bin 0 -> 368640 bytes build/chimaera.vhd | Bin 0 -> 34120704 bytes src/Makefile.unix | 49 + src/Makefile.w32 | 47 + src/apps/Makefile.unix | 20 + src/apps/Makefile.w32 | 20 + src/apps/hello/Makefile.unix | 21 + src/apps/hello/Makefile.w32 | 20 + src/apps/hello/crlf.asm | 31 + src/apps/hello/hello.asm | 40 + src/apps/hello/hello_.asm | 102 + src/apps/hello/hello__.asm | 517 ++++ src/apps/hello/test.c | 6 + src/apps/hello/writechr.asm | 42 + src/apps/hello/writehex.asm | 64 + src/apps/hello/writestr.asm | 74 + src/apps/pcomm/Makefile.unix | 53 + src/apps/pcomm/Makefile.w32 | 37 + src/apps/pcomm/cbreak.asm | 81 + src/apps/pcomm/commands | 16 + src/apps/pcomm/crlf.asm | 31 + src/apps/pcomm/date.asm | 77 + src/apps/pcomm/dir.asm | 416 +++ src/apps/pcomm/erase.asm | 26 + src/apps/pcomm/exit.asm | 28 + src/apps/pcomm/genhash.c | 101 + src/apps/pcomm/genver.c | 19 + src/apps/pcomm/history.asm | 370 +++ src/apps/pcomm/pcomm.asm | 994 +++++++ src/apps/pcomm/time.asm | 87 + src/apps/pcomm/type.asm | 219 ++ src/apps/pcomm/vector.asm | 142 + src/apps/pcomm/writechr.asm | 42 + src/apps/pcomm/writedec.asm | 54 + src/apps/pcomm/writehex.asm | 58 + src/apps/pcomm/writestr.asm | 75 + src/apps/pcomm/xmalloc.asm | 90 + src/apps/pcomm/xstrcpy.asm | 53 + src/boot/Makefile.unix | 20 + src/boot/Makefile.w32 | 20 + src/boot/freeldr/Makefile.unix | 40 + src/boot/freeldr/Makefile.w32 | 32 + src/boot/freeldr/bootsect/Makefile.unix | 28 + src/boot/freeldr/bootsect/Makefile.w32 | 28 + src/boot/freeldr/bootsect/fat32_chs.asm | 535 ++++ src/boot/freeldr/bootsect/oldfat.asm | 804 ++++++ src/boot/freeldr/core/Makefile.unix | 20 + src/boot/freeldr/core/Makefile.w32 | 20 + src/boot/freeldr/core/bootstrap.asm | 1309 +++++++++ src/boot/freeldr/core/config.asm | 1015 +++++++ src/boot/freeldr/core/crlf.asm | 33 + src/boot/freeldr/core/disk.asm | 238 ++ src/boot/freeldr/core/error.asm | 85 + src/boot/freeldr/core/fat.asm | 462 +++ src/boot/freeldr/core/fat.inc | 20 + src/boot/freeldr/core/file.asm | 1207 ++++++++ src/boot/freeldr/core/freeldr.asm | 1382 +++++++++ src/boot/freeldr/core/int21.asm | 255 ++ src/boot/freeldr/core/ll.asm | 691 +++++ src/boot/freeldr/core/mangle.asm | 172 ++ src/boot/freeldr/core/mem.asm | 366 +++ src/boot/freeldr/core/menu.asm | 935 ++++++ src/boot/freeldr/core/screen.asm | 80 + src/boot/freeldr/core/search.asm | 259 ++ src/boot/freeldr/core/vector.asm | 142 + src/boot/freeldr/core/walk.asm | 98 + src/boot/freeldr/core/writechr.asm | 42 + src/boot/freeldr/core/writedec.asm | 53 + src/boot/freeldr/core/writehex.asm | 70 + src/boot/freeldr/core/writestr.asm | 75 + src/boot/freeldr/core/xmalloc.asm | 118 + src/boot/freeldr/core/xrealloc.asm | 94 + src/boot/freeldr/freeldr.cfg | 7 + src/boot/freeldr/genhash.c | 101 + src/boot/freeldr/keywords | 6 + src/boot/freeldr/libc/Makefile.unix | 35 + src/boot/freeldr/libc/Makefile.w32 | 35 + src/boot/freeldr/libc/stdio/fclose.asm | 90 + src/boot/freeldr/libc/stdio/feof.asm | 92 + src/boot/freeldr/libc/stdio/fopen.asm | 129 + src/boot/freeldr/libc/stdio/fread.asm | 209 ++ src/boot/freeldr/libc/stdlib/free.asm | 37 + src/boot/freeldr/libc/stdlib/malloc.asm | 90 + src/boot/freeldr/libc/stdlib/realloc.asm | 233 ++ src/boot/freeldr/libc/string/memmove.asm | 91 + src/boot/freeldr/libc/string/strlen.asm | 42 + src/boot/mbr/Makefile.unix | 16 + src/boot/mbr/Makefile.w32 | 16 + src/boot/mbr/dosmbr.asm | 331 +++ src/kernel/Makefile.unix | 20 + src/kernel/Makefile.w32 | 20 + src/kernel/bootstrap.asm | 1327 +++++++++ src/kernel/crlf.asm | 33 + src/kernel/disk.asm | 983 +++++++ src/kernel/divide.asm | 275 ++ src/kernel/error.asm | 85 + src/kernel/fat.asm | 537 ++++ src/kernel/fat.inc | 20 + src/kernel/file.asm | 1131 ++++++++ src/kernel/find.asm | 512 ++++ src/kernel/int21.asm | 3282 ++++++++++++++++++++++ src/kernel/int23.asm | 106 + src/kernel/invalid.asm | 144 + src/kernel/kernel.asm | 878 ++++++ src/kernel/kmalloc.asm | 127 + src/kernel/krealloc.asm | 223 ++ src/kernel/mangle.asm | 172 ++ src/kernel/mem.asm | 366 +++ src/kernel/prog.asm | 404 +++ src/kernel/query.asm | 85 + src/kernel/search.asm | 263 ++ src/kernel/vector.asm | 138 + src/kernel/walk.asm | 110 + src/kernel/writechr.asm | 42 + src/kernel/writedec.asm | 53 + src/kernel/writehex.asm | 70 + src/kernel/writestr.asm | 75 + src/lib/Makefile.unix | 20 + src/lib/Makefile.w32 | 20 + src/lib/crt/Makefile.unix | 25 + src/lib/crt/Makefile.w32 | 25 + src/lib/crt/crt0.asm | 306 ++ src/lib/crt/ctype.asm | 1988 +++++++++++++ src/lib/crt/include/stdio.inc | 13 + src/lib/crt/include/sys/fcntl.inc | 16 + src/lib/crt/stdio/fclose.asm | 90 + src/lib/crt/stdio/feof.asm | 97 + src/lib/crt/stdio/fgetc.asm | 144 + src/lib/crt/stdio/flags.asm | 155 + src/lib/crt/stdio/fopen.asm | 313 +++ src/lib/crt/stdio/fread.asm | 214 ++ src/lib/crt/stdio/fseek.asm | 114 + src/lib/crt/stdio/ftell.asm | 97 + src/lib/crt/stdlib/free.asm | 37 + src/lib/crt/stdlib/malloc.asm | 90 + src/lib/crt/stdlib/realloc.asm | 233 ++ src/lib/crt/string/memmove.asm | 91 + src/lib/crt/string/strchr.asm | 52 + src/lib/crt/string/strcmp.asm | 99 + src/lib/crt/string/strcpy.asm | 42 + src/lib/crt/string/strlen.asm | 47 + src/lib/crt/string/strrchr.asm | 49 + src/lib/crt/udivmodsi4.asm | 153 + src/utils/Makefile.unix | 20 + src/utils/Makefile.w32 | 20 + src/utils/binutils/Makefile.unix | 17 + src/utils/binutils/Makefile.w32 | 17 + src/utils/binutils/ar | 1 + src/utils/binutils/as | 1 + src/utils/binutils/ld | 1 + src/utils/dosfstools | 1 + src/utils/parted | 1 + 155 files changed, 32573 insertions(+) create mode 100644 .gitmodules create mode 100644 Makefile.unix create mode 100644 Makefile.w32 create mode 100644 build/chimaera.img create mode 100644 build/chimaera.vhd create mode 100644 src/Makefile.unix create mode 100644 src/Makefile.w32 create mode 100644 src/apps/Makefile.unix create mode 100644 src/apps/Makefile.w32 create mode 100644 src/apps/hello/Makefile.unix create mode 100644 src/apps/hello/Makefile.w32 create mode 100644 src/apps/hello/crlf.asm create mode 100644 src/apps/hello/hello.asm create mode 100644 src/apps/hello/hello_.asm create mode 100644 src/apps/hello/hello__.asm create mode 100644 src/apps/hello/test.c create mode 100644 src/apps/hello/writechr.asm create mode 100644 src/apps/hello/writehex.asm create mode 100644 src/apps/hello/writestr.asm create mode 100644 src/apps/pcomm/Makefile.unix create mode 100644 src/apps/pcomm/Makefile.w32 create mode 100644 src/apps/pcomm/cbreak.asm create mode 100644 src/apps/pcomm/commands create mode 100644 src/apps/pcomm/crlf.asm create mode 100644 src/apps/pcomm/date.asm create mode 100644 src/apps/pcomm/dir.asm create mode 100644 src/apps/pcomm/erase.asm create mode 100644 src/apps/pcomm/exit.asm create mode 100644 src/apps/pcomm/genhash.c create mode 100644 src/apps/pcomm/genver.c create mode 100644 src/apps/pcomm/history.asm create mode 100644 src/apps/pcomm/pcomm.asm create mode 100644 src/apps/pcomm/time.asm create mode 100644 src/apps/pcomm/type.asm create mode 100644 src/apps/pcomm/vector.asm create mode 100644 src/apps/pcomm/writechr.asm create mode 100644 src/apps/pcomm/writedec.asm create mode 100644 src/apps/pcomm/writehex.asm create mode 100644 src/apps/pcomm/writestr.asm create mode 100644 src/apps/pcomm/xmalloc.asm create mode 100644 src/apps/pcomm/xstrcpy.asm create mode 100644 src/boot/Makefile.unix create mode 100644 src/boot/Makefile.w32 create mode 100644 src/boot/freeldr/Makefile.unix create mode 100644 src/boot/freeldr/Makefile.w32 create mode 100644 src/boot/freeldr/bootsect/Makefile.unix create mode 100644 src/boot/freeldr/bootsect/Makefile.w32 create mode 100644 src/boot/freeldr/bootsect/fat32_chs.asm create mode 100644 src/boot/freeldr/bootsect/oldfat.asm create mode 100644 src/boot/freeldr/core/Makefile.unix create mode 100644 src/boot/freeldr/core/Makefile.w32 create mode 100644 src/boot/freeldr/core/bootstrap.asm create mode 100644 src/boot/freeldr/core/config.asm create mode 100644 src/boot/freeldr/core/crlf.asm create mode 100644 src/boot/freeldr/core/disk.asm create mode 100644 src/boot/freeldr/core/error.asm create mode 100644 src/boot/freeldr/core/fat.asm create mode 100644 src/boot/freeldr/core/fat.inc create mode 100644 src/boot/freeldr/core/file.asm create mode 100644 src/boot/freeldr/core/freeldr.asm create mode 100644 src/boot/freeldr/core/int21.asm create mode 100644 src/boot/freeldr/core/ll.asm create mode 100644 src/boot/freeldr/core/mangle.asm create mode 100644 src/boot/freeldr/core/mem.asm create mode 100644 src/boot/freeldr/core/menu.asm create mode 100644 src/boot/freeldr/core/screen.asm create mode 100644 src/boot/freeldr/core/search.asm create mode 100644 src/boot/freeldr/core/vector.asm create mode 100644 src/boot/freeldr/core/walk.asm create mode 100644 src/boot/freeldr/core/writechr.asm create mode 100644 src/boot/freeldr/core/writedec.asm create mode 100644 src/boot/freeldr/core/writehex.asm create mode 100644 src/boot/freeldr/core/writestr.asm create mode 100644 src/boot/freeldr/core/xmalloc.asm create mode 100644 src/boot/freeldr/core/xrealloc.asm create mode 100644 src/boot/freeldr/freeldr.cfg create mode 100644 src/boot/freeldr/genhash.c create mode 100644 src/boot/freeldr/keywords create mode 100644 src/boot/freeldr/libc/Makefile.unix create mode 100644 src/boot/freeldr/libc/Makefile.w32 create mode 100644 src/boot/freeldr/libc/stdio/fclose.asm create mode 100644 src/boot/freeldr/libc/stdio/feof.asm create mode 100644 src/boot/freeldr/libc/stdio/fopen.asm create mode 100644 src/boot/freeldr/libc/stdio/fread.asm create mode 100644 src/boot/freeldr/libc/stdlib/free.asm create mode 100644 src/boot/freeldr/libc/stdlib/malloc.asm create mode 100644 src/boot/freeldr/libc/stdlib/realloc.asm create mode 100644 src/boot/freeldr/libc/string/memmove.asm create mode 100644 src/boot/freeldr/libc/string/strlen.asm create mode 100644 src/boot/mbr/Makefile.unix create mode 100644 src/boot/mbr/Makefile.w32 create mode 100644 src/boot/mbr/dosmbr.asm create mode 100644 src/kernel/Makefile.unix create mode 100644 src/kernel/Makefile.w32 create mode 100644 src/kernel/bootstrap.asm create mode 100644 src/kernel/crlf.asm create mode 100644 src/kernel/disk.asm create mode 100644 src/kernel/divide.asm create mode 100644 src/kernel/error.asm create mode 100644 src/kernel/fat.asm create mode 100644 src/kernel/fat.inc create mode 100644 src/kernel/file.asm create mode 100644 src/kernel/find.asm create mode 100644 src/kernel/int21.asm create mode 100644 src/kernel/int23.asm create mode 100644 src/kernel/invalid.asm create mode 100644 src/kernel/kernel.asm create mode 100644 src/kernel/kmalloc.asm create mode 100644 src/kernel/krealloc.asm create mode 100644 src/kernel/mangle.asm create mode 100644 src/kernel/mem.asm create mode 100644 src/kernel/prog.asm create mode 100644 src/kernel/query.asm create mode 100644 src/kernel/search.asm create mode 100644 src/kernel/vector.asm create mode 100644 src/kernel/walk.asm create mode 100644 src/kernel/writechr.asm create mode 100644 src/kernel/writedec.asm create mode 100644 src/kernel/writehex.asm create mode 100644 src/kernel/writestr.asm create mode 100644 src/lib/Makefile.unix create mode 100644 src/lib/Makefile.w32 create mode 100644 src/lib/crt/Makefile.unix create mode 100644 src/lib/crt/Makefile.w32 create mode 100644 src/lib/crt/crt0.asm create mode 100644 src/lib/crt/ctype.asm create mode 100644 src/lib/crt/include/stdio.inc create mode 100644 src/lib/crt/include/sys/fcntl.inc create mode 100644 src/lib/crt/stdio/fclose.asm create mode 100644 src/lib/crt/stdio/feof.asm create mode 100644 src/lib/crt/stdio/fgetc.asm create mode 100644 src/lib/crt/stdio/flags.asm create mode 100644 src/lib/crt/stdio/fopen.asm create mode 100644 src/lib/crt/stdio/fread.asm create mode 100644 src/lib/crt/stdio/fseek.asm create mode 100644 src/lib/crt/stdio/ftell.asm create mode 100644 src/lib/crt/stdlib/free.asm create mode 100644 src/lib/crt/stdlib/malloc.asm create mode 100644 src/lib/crt/stdlib/realloc.asm create mode 100644 src/lib/crt/string/memmove.asm create mode 100644 src/lib/crt/string/strchr.asm create mode 100644 src/lib/crt/string/strcmp.asm create mode 100644 src/lib/crt/string/strcpy.asm create mode 100644 src/lib/crt/string/strlen.asm create mode 100644 src/lib/crt/string/strrchr.asm create mode 100644 src/lib/crt/udivmodsi4.asm create mode 100644 src/utils/Makefile.unix create mode 100644 src/utils/Makefile.w32 create mode 100644 src/utils/binutils/Makefile.unix create mode 100644 src/utils/binutils/Makefile.w32 create mode 160000 src/utils/binutils/ar create mode 160000 src/utils/binutils/as create mode 160000 src/utils/binutils/ld create mode 160000 src/utils/dosfstools create mode 160000 src/utils/parted diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d2d3788 --- /dev/null +++ b/.gitmodules @@ -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 index 0000000..c45ff74 --- /dev/null +++ b/Makefile.unix @@ -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 index 0000000..f728417 --- /dev/null +++ b/Makefile.w32 @@ -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 index 0000000000000000000000000000000000000000..a1adb6ecdae438887f5080a8dfec7d39a758eaeb GIT binary patch literal 368640 zcmeI531C#!+5XQgnaMswfUqW+Kr+hWCF2qW!V(ArxP&3W$v_~KLQq-=b}|!cYcY1( znwyEKc3-q5#p*9` z=jb#se`wXITrq#Rw_>DseX6D+(epYJDr7SbCILb#%g_*L%KrA&x-Zp5wCqf(e{99TO2#{`=zdEPmAeR_s4-b=Jr`} zL*2P%@2ufw@129PKB~@75chgQ+H%bfEo=NrIFbTep>zuq-zat($Ly7U&eB6JyDkY= zshO09J1Kc=VQNiN?Ln_Ltz7%G_JEWbG9dm>Ec;6q`s_tJqL^)dK}W^V2itNHOU3Z2 zm-qd3-(RDTR=w7sQdiqE&b1CKH)I{hTI;|?3mx;^`&x&3t#Lf2nw_ehwL7uX)1<-` zk3GAz#Ahv-HS6}g0#o6_!pM`obK`|jsPl)R&b3Tm$znFJxF(kH4l`7S2AEU>r>h2k zMKz>SHEe@wM3XAz9aUOoDBYwUJzbso74P|x>9{ME$MBqP>0KNbJiBFBvOa#6d z0)33SXvT`}4>>{(>BuVd{T8iY*+=*ln{4@@L&{;zq|s z$BoRK!`RGucifSipJ&4FMaNC-r`SV(hyW2F0z`la5CI}U1c(3;AOb|-iyEmd6%4YF~e0dbF(M$$#HgIKSZ0s#jX9#~EvX@gDb(t+|aG?}YTk znb78c;Lw7N?kF5nvBwrIEOzMZkJh|i+p;~5J+!`Q+c0+KiOQ)e=5T5Jzh<_&47RDx zjQ`{DUtpW;MYaMcIhK}q ztxauGn>0tXp0wG*w$){Ds);UEgHcZ`tj&?n-ZR>%7*#d+o1}v--H+DgWhh);(A` z)@dv7TALf8*m_sh35k(MQek&Thv-}67;})XwohTkb%_nXQHj>hhVQCHYgZt?;RSi? z7~fi2!n4f9lBuR%$yCh&F8k^uoSJMs>yDaiZ+FG>hh=Z)LaJ9HLaKdN5K_&zx4px) zSpRIq-%uj1*;lTKV#ZWCcCb{`S-QgcMPke7^(Vdgr`tYkJ9w1dMFO$+djw+dhXrEwtwS{>P38KUos};e z`|86Ugg%Vtfg&j7@QO6qG7LGf6-c^N&r8}Oo!~``wJnyAS)8TSFSQrxQfr$mq3VogEfWuKj&5>kHU>Jg znl`5CmzGpz$mv3%spAZJ@^=TF-;~}D_9ow(cp}~sO5g1oEYwNyJTBA#o)-1QgD(5r zzz3;ZIV~QvHAwL`X~9UOA+5p4Ec;Q)OXVrp6zY$~+jubX;HCy$hK-*ujgwClCIXE+ zMyQL;m?PAyGxSQijD+#>nV+ceNa6&Z92w^E)JSaoY9x64bfnavS>e8C^{VB|T&1Sc zGMDpSQ`xdLrKXi@-DN8vfR-x+eruNf+hUm|BxMJkshe$LXU9>o#qs_9?!@s~suoWu z$N3%>6`CD6Oc1APGn9lxo|q0#Oda^-3Qx<$(-Rv>oq=z4k3i}=Ml^mkUb2t8?9*~^ z0R5kq`ZGPPJH_`rC$zGy2>z;3yALsUy@yH5KP4u~L ze(I@X9U*H_c@EVhYz4Tx)Dht)F?s~HjQn2XMnL2Kc)WD?h_sT0{)gC8Pl-OPNpEyl zYmw!n0Z`ZBZ&1E!MX5>dB|t7xx(2R%e9fxz@>OMbneJKUMCNmq zI!&v}OsiL|UMnnLc^AUF%f4Q=c3l~|67F5M*16)MqhG^e(>3fG(=wOIbvMt(NWn^k zFDpgZi~l_Q@Lzt)*!QBJSi#tn(NoZcIX!0V`;3i@eRvULi(*ld+_^PzOM-0eU?o;w zS%MP7S2!P~fg;IAx$|s-$~op@15Kz-ekS2ECfdzHNA`aiWFrl0TMYfoG&vAA)COc7 zm)FCl+Rs~u3Yye9L$8MayLh!17W?FT>f@Ub9rjJ=dj7N~tLbBSAG8|bjM3ES)S6rL zjD2`A#7kUd%LeS{mHV6Zgj~ILxH772A(q$VJJ*P&R6@6mu=Mo`!6YC7U z7CtiL3kGiF3w3`t2;St^4YGrTFj?1vmWwbsdAGr35b9eDf{0aa?yn0feiK3+0$$#8 zLNWON3-@dX z*uy>RS6PvZybNBH>r(ASh4XExIy)~%w$~YI_SH5$wEiu*oi1#6CSjvc_iVx@{wT0` zoiEI`zA5`CJvIxj_d{Fwx^H*dU9|91m^1)=_R{+lJ# zzs-NI7wV7j-y4PcXA>NDvv+Ye%8vNZf$}Ki=fH?L?vo{p9N2wJ=m2l9V{H=86Oy+Z zDLnX4#an%^xtU+>DIOITe>Y(9I$yla7e@?BOVaeb`t!V$vBW3ex|)~vaw(4_n9be= z*NQu1+FS+Z$qO>p#q*`xYMz`os$x2hkHYZ`v-kF~9jDUwyW^0ORBV}~Z9$!qD)E51 zT3>Uh*0-_7S9?g00@duv8>KRP7Gy9Kj=btcG18LnkK#nc}wt)n#`hJ2qo4J3tDo1Q`X^$f1oUf=*dN0;FQtBR1ywo{FY%bKn5v`w@H}~G77gd!9sKA{zSv`sFE*ZEY?H%=GNlfER=URD4ul_B z5_SfL*EB~SMueqVyjck8>IXW)chcGW@bLC1&rg05uoiw4#KS=4Ume8rD45^pi7Z^y z`%GNdDUYGu?72^^a;1r{ODiuphvE&0iac(fX(NvtPp)SZSx0%Xof>~F>*}uYgFcHP@4nu<_QK;W(@UK-}B{e+8 zh8!hD{K|6dya2KnZKyZ!?xm@9cs7>Zb$>L#?9$i$+2BoXFpSeZVcmA0+V91ri$$DBJOJYGJ|d_hvt1@J`)o&}8Ex@IB1_yFr}# zx?#ib4Zr9xZ#KyNdD(AZ-ys9<5A+&OZ%B8cv!K`v1pHN ztEx5GrOP_rnjARm@O?_8t;5bse+_YX^}7un<~l?D9)n~{6yHG^U}U_ka-~dn59hH< z$2-bP?^*+E-n6!&)VXr?+I6slY7VFl)~`!b`g!Z`P4iA&mu6|2JoVl**P!`DI^N>h zR>{t6(l1@;X)y-S=_?lnUCKT3yTxse2;ZjJJNS3vf*^j(H3{M%PqR93^t}AO6gzkx zLaOkRZ-u?6t$)FQJ@WPw^7eBHJN_`VNcz=4ltOs+x9-@Ct(x#w&W^3vS|8pLq+uPU zPUl+ZB-6@et5(CZbgeb5Tm}1X`P#CTtL}0;m$_E0EyJ$W+|;ubNv5;qV-c?u$7A5` znpZW6_?bsh4yaLm$7ZDOc8`~yY!6?sY^~fLT2)%EG={j*sa!R3IqBZGR2|B&LuT)6 zEiyz%dNm*$uzL(y?TRfackDN!WB;IdzU|$%cX{{sn1cm8 z;o?cle!-i)+u#YpLw36s{nv#;D0!!WyT)cpiJy#l6$a=YLr-sEdb=x8&>(WhBAmCw z5O}rW8WiZBrs>?LHJlGs(+i7qHHXIdYJECONT_?>0IQ;rFaBcK$TKL4`5kdAJT}m1 zaJYvGb*;R--fK{b`nop0b-=J`d-33+ZP#E7!C&1y;j3%cx+bi2mX@ww;f(z91_B%Q zgTaiY?-|Nicj28c6bx%zF>K=7 z)M_;Ccg1c=kRD3d5-U|D@VDEhJd>M-NpB~lIf`0zXU#Aqq?`i|DNy$-xHrZT=57)-tlKAvP zsBDg^Yu?}nTC0&}H2ON`_kWv?ug05?4)MRVtx>?w; z?2lrq`j`~aXW0!C#nZ-Y1%>lN*-Dmqx>{C`ZBr;siVex%fS*v7S{D&rhh5uQJ*ljjO1b|EnQf5?u#RFmJ_K zyg{pagUL;uj#K?om*6%k+t0?zF^O`Z8}qLo%H&SEI8c+k(X6Ib7z7 z%5j*R{CNF<6g8c}e% z=XP+-?%JI@UQEF(1L&))$jO<2J`}-~m$S?ni~dgCGp6?arhSdird0iP%6oBc^_D21 zlAH0uEqd4NnSs+AkL}{&v^f*p9a~IiHa5PPqNLx^>GPb6bLzGT8|Ma|cp&s*ic4>< z{7y)4E4v=qV)C5RR8(&~)``n!HSuW<`h-5`8#Q*^_(_v|9e zb!oLtI@qJ3nw`Sr#C2)Td+~E`TDj9)Ipq#?#u;%v)l97L3#(_igqmh+ZSx%WKKZy& zn4FC;v+#p3Qv>OdvxmxOy9b!PcW82JnpLmXHkaTsfnQoedUJEs9p>g)s+m}*XPCt$ znwqBRoq?DdpJR-#A)1|&n-XYapmu1%lna^jj{e&Ya>&Vr}1y#Yq%SY|7RFyyF)Yajq(LGEvmh>E#kp3yTUMV zM~kmOAumkfb>+r|E1Z_1uW3;dz;Ci;c5O=yk~#)0iF?xm>KdQErfG~1H`#Me@7*i6 z14B}_>t&NT6}=wX3|LqP8&_+q_Wdn3AuCJVS*TP*`$kI(^i`7dp{{C|^q#IUFxu0l za%&npMoT$*z8aO)B(>^LiS5#*6?fkH%|Y9enD^#$+_-c{Prljp$+1&`jcKyw%3lxp zifBvL{r70JKa%;&32R~7=q=+nqT_bkXmo7jEw=Ku*`chDgz7{gBiG}Pw(N(Iqvjo+ zcBw2HFU`bV6>4$Ud|RQ8N5#)Bl!ar(anYM|#=FnY z4V<+c;=QMXbH=-(q~%e8)6Zyw%~DBd=EU>&y{|M0BwHxl#8>KU%Wkn5quc1s+i+b* zn}m^SOA|)GrHT-bNso9tasy{E8%np_oU}BxSlb!nY0!u8fP^}AhByDL#}CTuw5&N0 zTlH#Xvl_|_Yml2LunWA_vsKNqj9?p6KVwtwQ~CtO_SsMcmR-{55O90ecQW^Eetv#8 zissuUzTs4hZ{+@2&0fvgFa0Vg?vuWK0f^AL{4r}mohEnqi!Vy|2NlBGY+;7dnjmkf zRCdpC#Z`9OFf5edS{67_8C0*oQCb{)Ml0PO48DrG4k^2(*>zpkM^&dP{p#ROO@0vF z=@WOlnxvcfX_>)bvwt#B2f=uAC_m^I@Z2sw`NwD&`v-?AKUQZQuR1whV+~5PBK^+s zDEegsDY|gJF0}}@yO!JT(Hz@!{~sCu1%0`Sm-&X}7D9FQbs4aUg^XU+g_2Fe87sIG z2Q*osR%1gWGVBkckev&ZK9*CWk3UTzL$xcsW6`w-*^6Af(Q0gL94-AxleIs*rOWW@ zz4PQZ2V1mVbctl#-=-#l`Xrg)X7Y_Zr9p1Xc;YEwtDrwCT=$K&ULh3n5n!JZI~71 zf*?fJ`D*VUTPiPyHhd3*4yezD3XflxvDMIO4E|N9G7A}L4qR16KPqgSiY4!~SWhtI zos*1-zL*2BRC9&8H+WC(Aw!Gxm|`SMvr(BAV7m@l$8$IQ7U}%YHHc zLv&Dhp>42siT3WmXoTZY_Jot$B(Mg5k9hbQV##6Pc`kwD@mjmQ_HJ*!BrTPA{{B zkD>Em5N(0;w@p0bx(OByb4`$*Zg*ZI?YiI`)ze?-1%V=Uq&aMKMdQo~?x?_@i_iIr zJ5iov1V$Nli43pa*@)4{-5qCg@jfEK?T)R9+N@UNv5qB?kw)~9qFOm?{%q0}EebmO zo#Nr%`JMO}%90XXPvHzyR-Mh*EOs#XQt#A&n=FHxC8kE6U4cX=^hRVi;j_I{c z$3Aw*ka)*0EEY~)TJ-)MrEAt=P<5qy^=i|#Yw$v@T|Nd~70N|mV|uO8UOTUKYz21d zCWgm`d=}HG^ty(l;#J}jDY1WC&eHyo*^3Gyk;&$7s(7TYjZ~@FNbY+T6U!+#);(R! zrJ3$36`Nr%Cl>0^nR{mIt*z<$;_^8dY~MPkHNDt5TRZ||?G`&CtPMvA%L?5=a$RC+ z=Pw$!))vaPQ_YdtwMUNm(@Jc$zO8dx(;c1qMSRRkxs~v0I4jG5`z9no^zmytqvUK0 zjFIe%fj1zs?3Rb$a|4~?F2pHkY@4pus^u5b!)V~~>g*5{$^?d>cxXqTz50Q7naZU> z+oH2XkA$3)mpIpRqIYC~*ZUQ*XdHYUPXwKX`MQpysGyd>Kx*bA_9A?o){5slTc;xR19&;GEr{0|rgnceC~9z51fc(gA$5@g7-q(op#lEYm!ScU3{(6I65vk% z1DXG(5@0FgqLKTse79%9!HdT1FFt(P(fUgzzphYH z8{8xT{$zhw4%b z(WaR%8_MCnoG#ug(8(9*E^D!#<%`pNfzF2(>&JW{_eFfj*CcLV>(Hddu;fv(`GMx` zDsHtKxzG+>399)8ikAkGxlP5g+OdDpLL8}4@r1f# z7gr`=SYo8vdw;4~vrd^6`9pENWUiiV{DsZjahDlRQ25DEyr4Sa^MV-S!Y)u}FLHqj zOu2Goh(w-bS*$pTS(VWjgB=6R9qYnVEq99R(UxndL^pzT4MqUjwuYCR#bv`t)xA|CcM$H~LFXm4zcoQ@t91e5UpB>sPl|DE{Xj{j%z z|1|!e*u)^{2wza;(s^DQiZKB! z(Y%neNvuxEqq-tK2>Q_ab~MRjF09bMqD=t1eHBW3ZI*O7L`T|q~h zVvOiW(~KAENW0>A_EvPHU2*+%q(=0GN9Ka=t0V3A>M^zeSUFOt%{~yAJDK-UromUu z*2h;ZppkZ;mwU9nks!UDiKj08E)(kEHCR`du~OerfMMrTT?6ywP#3YGNh9kUMu541b*dX8Pbsq>8%XujSTT5f?(I) z4C${K((VkYIYaD}&SqfOUoxa^8PcCKq-Qf62!cHuGo(LcNKa%)b=b3y@A*ZB^wSLK zM;X!&v1dEq^Mee@lOa`RNZ-Mp%^A`QUDESi3NKew!~M6nrc1fZ<}58QH!Ul>m#db! zZpB&3dt!Na>jLMpd-$G;(&etTPE*z-Q{Jiyu9uF;b-0q5bzMf_`_JinlZ-w3-q}W| zQRf;jqwl@UNtbOg2-T^|seSalkys<`26XOjNHRj+g`PO0k?XsJx}ipNk-$YE(}+I9 zYmCA;-9RIRT^Ly!%r{2xjbrV6kSN*s8Dw59(07e7Hnc(3HO>f`*9m2N2DEA8jN$s^ zV!5%=*iUYJosk#RLftf;qFiG{ZhW&*mK#qra=G!%M#zmP8oAuq)*X=>BjBgVjsLYP zy?%}GJ{I0T##qj>J~CI|&gHdvaus?QexX;@@It4% zV1}&WT?X~;R9VA2)qN*4yg3!~V2$M9_*7UP*LR$P>(AN43lBy>IG(*F7Qj9W9JXxUcck@0-eVz6xRp<)z@=v|;}d zW-qcojX`dcD{5nKx4XUFXL9RH`1pT`uf)?FU72HY>y%CCRG!xGGc{18D7)<9>G?$v z!ecypc+PvSWbugjnyizV=87^;igHKIK6WNxfR@x};-hQ_8bhHHxHy+6R@>O{@S*vE z`x8Q3(D6qVjM@az`c{qgwSHrYe78JiXf*Pk^Mj)OP3(d%LD9h8;l`P~B%fux(r{z4 zQ66sOFDaUKK;^Z{K&9*Q1Cbm35{;*568C(z0sdna7-lv-6o{G=6Xl>HT5#mkUBI+LvZcesYyxTa=`MsT}!~Z!Q^G8FVW0r<+ z#9lf&@>MhnflCx^2@0%rpmN))6g zPY&Oz-^+vzfyfB~oG>8_&pia}PA7xiN6FB^Ny&ilZnD2V76Ih|I>d+oTch_fn_YZu zb4~`7TsxBk?In)Avc;;6WJUfPmWEeV1gq>Jj#7Nxn*e`p({7Z<2U&3UEv=AC?PYM0 z3aE~7r9K{@d;FG!jpFN2KQbhylqcpZJTb*QG4|w0{(wEQ#2*_w<^DuhLS^@D@as)* ztpW;Mng44cX$p&MED6c!wTE&{czfoBa_)x=drnB&Ie266W&gC0obIYM zs=i6wyCqtx8;q9jql33Z`+q(-f(I@Ilao;(4WA)QOpcCsCf(}kQkUzYBD=oZ8HE;8 zcU&YIVZ-^joTzeWV)0zNbQ8{g5cv z52sY&`r)@-c;4@-E?Yl98*ERtwAUW|vg(Mm68$B$#KC`DTuX=@x+301oVMdQcWiH} z%vtP8-m-Y3J+<}_SDLQC{09(}o_Qjzq~UlPD%zcx>dB?S8R8i}dxNJlcilI*CS)~a z*%>*D-Er_ydLIgx&|=q-tm8K6*MndKMWZx8Jb^q%AeZ;yzRWL!YY9+4XQ2vaE*+MO z-5Jm=hZsB&p@3^x%;5Q-W|M}(kw}|XBDT!tuU0_Z82Eu4zgsm=mdYYR_x-%dfm?vq z%sq;?c3_Q8F`Dbuu%ME)OrG$ewh0}Rx#*Y-ESC-paNaH%;+(T3pTRlfimIq-3oh}G=#oaA@(=EcoQ`fWv~W>!Ze@zAj*r zjTOB;)h3%TJr>LtWxQOHD`$LkajtZvmB8v~mpKipYy-a8Q}`yHJ-v_pEyT~9cU1#ZCJpH zEQm`haYCNs9-=QU3FxrE(}~=`IsbP$;kjMOs^gzqe~Z6D%`2K9UN2Jqpk4hDU;KkFP6?X=dZ{{I*x(mBBN6(qLs2W#`vqk953oq(t!#9yc@xhL zOtrz7y-D_K9%J@St36@~d1qNC?sJdu&XPMW+%X)7R2I{x??Ub~Z$U)u;}KCvn4H=< zzWh3_!pGam9TwaviheDbtNS6Gj6#IbvI1Yqj8W~G8Q4|(CihjWi)H5eDpnVdpK4Z@ zh@To(hwly5*D^<1?Tcowc?L7rCg&lur6yy}lGG0b>D_2vF*Q~(b7+EW7sQ62v|_rq z^TN4}7reZ1PM3}M5sLACgHiN3prOOC!8-0wI6fEi$Vs6yD1n<8UX!Bqou{oC0gbn!3-sdSYkl~MjmPMNxk`_!PKms7x23(!Ts1Eqy>h3e?$dC& z@7E5KmYsBFh952;so-VDt?hkw@K@b`OM8!(H$Mr&({uie_OZfPMH&oMw(LC9Hyv5W z(N)m56|3K0|HVZ?@xn-F17x4^(u{vN z2lUX0mhp`Hq|c6qB%m1f3G$A&4BD0p4$&GCr8#rv{NzzjQ`{KI;ZoZkbCg5VzQq5x zGv{7mOz;ZNW_Ag+Xf=o@&U;Qk#Excz7tMxbo&#Ujwpdx~=w_?>S1ne}{LGsCs0Yis zJNHBibDRT@&8v^pq#fh$bmQG->4tbI>6oS66C7GTgS&phTTq_lV1RV~D2%;7#Yvmv zq(8B)y*@6ZN6L)4ja>$GbZei+}H1V zA^OtN^sU1#>l3}@{VVxIw~r6|M0bw&PHi90eWE+ZU*0Dg!vQGNvXn7Wjk>l;8SZ;7 z1~vkQPUQj96Dqll*ubEsmX4@4%?Io*)cViS)R`m0E8+w|%I@yUc z+}4$Scjd7>eYsgW``$gv%2qA!>jVw;?+RJjZ(8A8Rl%K~v*pose@Q4iJm9<_l-hrA zHjSqu(k#x#m~%G9oU_AY&ixv{*?jCdJ2G6{?-1I>I4~ePGHl$pUEF_w81)5;27bHJ zf@2Dfeb~ItxV`TKysAez9*p|HJ5!jp91}I25%|-G2j+WRbFA3Vmi^CnU)vZnrh(lC zk*Ycn)A+`<((N(QxFcO>1Kl&g2;*y!*@b4VU9)Bxe8=a)Vb^(&lg~567B5$J3iyq@ zRK356@r>yjGZ`CJZ)VK&C>H6r4`Xc9<5(O0O&ma3SETDJVa^hL(mybu`&rfEJz{Zw zb5iW_OP;i>@;0qeWaRMS__`t@#}ik|S=2fs`bfRq_bK(HTd60@`lfA}tn*G#bl%c+ zs6xuEka~V5m zGWWS$d|98%YsP(=&*kE<&t>*FrGUQJ=Q4ZTm3=O=$H7>aeJ*=KD?XPK!cLc$_ql}8 z(#PkreLO1f2N>KgVZ(gu3Z8@!x64-fICr~jAMd;aKL}&}bhpc&UDoZAkB4CPx~P9o z_ewknEomq+=f!;Bm;)7?5m<4;w= z)vM>!L+>rZxv?st?u;OPJ5+9vr}S(5i6H$*>+qjO8TpYQ)SnX2Q}+*nsnDU@qGPPp zBsT|Jbd@Nd2@#tmIeSldHg1j9o&l;pOz>BWrL6f?whDOoeEq_l`T!3FR_!$r1lsb41lrdnE7yCJeyQ8{g$svAM2_)x+kl zt7i4Ex$A0JJ#6l}T2^mljo-{Pi>WotT$5NUryMUNiU_bopKzL9T77}XbK+RfZXo8< zE0mV4b>DS&r0C-c3U`_59_QM-Fi9NBi!KO{V8qwJhKEOKZ8D&F%>mvN0XlE?KZF-p zOmTx+jamGDTwveZ>qy1RcVprFN8z&i*rSe2%#6lPx<|ok*gZe@hdafWVs^W<;-0`L zw78z0en5(8a%mb>ERfWwMsM3m8^ZjNoy0y36AwOykpww^e2PQdmo!4PCG4Q~X(LoM zkUR8_Q2j5t#*H)jvwKI6E^>|AmW9^bKj9j;E$b?-ajBPejVtt~Nw0Jke~Me&GoRlr z?grlRbCa=h%3^nXPdAWdci2B}vFm)k*rE8zp>n#^Pwqk|{N$egG(Wk;@RR$mf7wrN z>KpPaq0$Xmjl*DN943m0?CL3fAPF)wgh>|9!0vcv}uJ2+Wkf=x_=5!P|a>P>V< z1>)OQ#~6EeLpXY}HGbVdcY?Tw{HyPXdL$Z#rLK@%ilZeTaEn^-oxncc!BvPo<*%VAU4R5p!GXUo`E z*>bjmm9mxWE_OFt#lFVA&Q`NEtc@VyEww>)@O>8H7k@?t5>}A%>TG%eOo4vyJu)nfa z_A1+px2uiqX9w8d*x%V}>~(gKy}{mOhuB-}ZFZO)Vehb`>==8O9cS;c_t^(bVt)1^ z3$PRHBla=-2Rq45vD54fJIg*{?W}`!vU9A9ooC(b0t>Pb`*+9zxoifT$@17NW@WS4 z95$ET%5Gz~vpZNmo5yTyJ}Y2_YyrEI*;x^Du!U?d96#0kA?BI7TtOcV>q%MM~-hsPtiaw*}&lTjxIHHQ`^6#mX5CL)q&!(ho4}n070iZZLyN(eoz8OD_|&${qPo?C~=(vC0rc!Y8eW7Mt-I z4{P8M`pnQ{Eh{wbg-RQihfBESApcN>cybPJzFM0262;>crXTtLI8Xdf-kOg0e>UwH zYs~tn2s7$nCYhx|-P9zZenyf|mzRXcmSB^%Vh(R)6QMpYNqRrdq3?V}jVXNasRs2k z39ac^#HS=>`^fO{hzc zwn?k`#K`=ZOvIcI75Cfi>3Y0GP;0CqrV*uc10S>xZr8q@XCssYliLCk}S zNYqXP-%~UIs3*Z;?)o54AG9aygUrSGo8+g8L(2O0REFVdF3=t;3%3$H=i)Ko2jv!K z&5YTqu6nUGeXje6=bYC0rV?Uq;4}tnafnBSDF$KCAo3_DW@Y8yd)awm>pa}T59JGL zq-QQHlv5QAg;|A0s=vU$I@7<;_pmO29Z~>#){z;qeEPwp)`hG30ENa9L6CdA$~uT%>YCjR)uVbeKIu`ESk~m|p*_ z%DK(u$gyGd8CBq&oEZ0bjEgJawrL^P!D39?7SntbZL#4;f`ZPmXd!#q5!eDbxhW^w zHRP7o@+Wdk&J8*DuY0uj!960KRRwC01$*i?(?___ics%^DZ`Y{yxzG+ejtSy&u*NQ zR47fxJjvSr&!$*@HkB9DZVL{`Vz_G+G2AaO?YA;*bSz@#zAb;}Ib?ip)r(sbThsmT z1|_(>FAxt~nxF&+WTfGpV7#fy$AQQ4Z_vq~pgScVDc#Y+ts1u(OLWA%XjveC$aOJLexKR2PB-#8<;zeGAN?&784bN;4l!M<<4!TDa zO0_&XUL~u1aC6(TeB+k28@H_47)U6T%6kvNntguU0NGopacq)!zq)3rRuP?O`~!o2 zV^Gpx@Mi_3>~8 zc;)poSmN+-woVpLx26YljpYf_${6k#wHy=XyVkBXL638D9hXz)M1DR&N{dNDG&A$~2gc<;Gg0*3RVsh~Yq{I${#Lfd7}!j!Wv{(L!)WhVJ{_!m16f?f6V91%qjlu=>l7ojS9dXi9;oSVd(3r*ny z^~^@BK0d}MYtSJ#uc&l2DNIkt3J1kAKRK^jHeL6;+S3TyF!oP@2Q%%HClf)Z4l> z59(>%ng-dVb86HNk;CKIxed zTb|w;wI1&o;YRi+k=d z_a!9u-$8FeiX&1Sk>cooPjd$A<>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp zM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>>Y5g-CYfCvx)B0vO)01+Sp sM1Tko0U|&IhyW2F0z`la5CI}U1c(3;AOb{y2oM1xKm>@u7fay(0bU^r9RL6T literal 0 HcmV?d00001 diff --git a/build/chimaera.vhd b/build/chimaera.vhd new file mode 100644 index 0000000000000000000000000000000000000000..63ee89caf0e6144faad2c6290972a1cd134c07b1 GIT binary patch literal 34120704 zcmeF)31F1voj>qrCX<?)Cn203yZ*Pk z`$eBQ-fQ0X^Ip&Kd){<)H#Avl_cwe=)HXTWosq4=aPsFLj1XTEHM?r}JDV`HsdmpF zg!#<&ZHD&PD*v^CX6u8I9)tIU>J#~EZDq@St18QF_m+8mt9+~0uCc9L>tC}XDPE{w z72ag~gHwCHb=OA!*bl`0LZ~xDL3!Bg)CMXSCwj?)NM2q#wxF-K8XH!dR%kV9EjT`Se-7?sl z*4p;qfrT6WslnNC^%g^Lc6|K+LxY&HEg~>F)L=3;iu;3i8aMb2^1D@-gj}=Uf9}Es z#ZQ~Io5a2*cVti%LA9-s%6_-oL#3nL$ES84MyJrgh&y ztj9Ey;WMwzT^m31ES!M?6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>s)zd3=h=aD-Li|6Iv=x_?7!6uAy4LgMxh`@;6r~-pFP-x=}!hGH~REe>VZhdCZ z%(?UK%$r@1XPaN>%3FBD^){QWtNVj;(PR+_B}q<~K_t(K`yXD}bf&s!`j$9EY9s~@ zO;hrRRUgk&@<#+KM+MiX#Z)E-UK2{Cs;vKDgUk9OcgIS*q1n^1GShHuV3*=LsuX<` zbS1Q^t?FFGb|54B4lH2{Sc^0cxBD}*MoSkA1-ZfzCf$R@A zXF2YO5uG22X{z+I@O3va4&aO_(p>iuHAzss{Yqum#)&J*Fo8}g?|9A)Ccu1JdC zGNm)(HJ%PBtpU{-cwKBLO}hQs$jnDO-ogKdKgPI@#uR-N>KDgi>x*Min#Zg^7R*1< z`a$dd!(FZKx4s|aQU@1(U@lbSMTx~8jK#VcL+*l(%3%++<~jFvRF0^AanGOj{3-5G z^{WjAjb>sys~`}A#T5D%NYN25eWxSfC3bt00sUJ2r&Que>?yGf8Y@3CQ^U` z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZK!N|!0-cdaN(4#1_fP1zFXE5}AjKmkASEItAtfWFAX$;*GXn632*hBd zAxJ}!QjxAg8iq6+X#~rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZ@V{E1GZIOOAj$Xs$%3tpLmGe-kCcFvh?InsjFf_8MH+}S2x&0V z5Tv0;KG!ZEq$%%A5(hW#ABHe_PgLE^}El87)Zbg#6os0J=NK=ufAx%fhLz;m!6KNLG zY$O-b9HhBO^N?;sx*bU_18@9C0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2E_R}0LXJMYfC*#&vF`Gs*pEP5c~iFovPeY0oGpTE$i|FfPyK1Q3s zRWN(@9kU8-g^LPp=Z`mwMdO6HeRe_q>^p3i7(YtbbA^~W|IRz}@@Lube!={c#Sbuq z|GroOM|9`n?UMV~ac+VO#_Q|VyZ2F- z{`ns(D*j8>kPG=D1y+==Ec37SX;*>eUs-ieS-H0?evEI`J>_ft`cP+feE+Z6@$sw6 zzFfZA);G1B*SE^Ix*YE_ql>`pBwh~xTDf-(rnODfKR7DxtBC(1H;2pqi~?QV?gfvv z40_tU@9nMM5o32L%|BV>seSFa>2VLQY&uh&|DL;WLBV6ye{6Og5u*M1d;M2!$!pwr z*XfqQ-lW#H2M;XV=#RxXgZRnfMI|0{(PK5Q)i!TS5D%|!+B#gEe4=WqL3n&IZT}+N zb(vyQogHZcl0$4NDs~q*n}U_C!S(xMDno(Sgi@(0>p$4wdhti@j+F-t&7O{xuN#gH z>{47um7JAx%v17DDf#W5pOjh(+~MQ` zccI!Nyh+OICF(DYp2g}N#&EdAv-oM#zHrSB!|Sy>vfDQlz2`h|y6y2n+KMQyQ;Mto z(yP<4@+HI0fv+{#M90dV9hFV;i&A-1Sua-#zvvyO{z2epN8x89MV;P}_}RPMg$<76 zMvG{%mUxz`S7Rk2MP1=H8-)4aEzaG~&L7rd-D1p+IQPm4E?%+DHp`$Xohe@9>5y}8 zKs5&55F1LLzx~?C%#L?rTt{PyJ_=3gj9h8-gI$pnza=`6(khqndhaqG?RW?O8~%tT z4aSn>UM?zjHf?Y{|088*aD9_=uXA_MwJW2^Zw|Wt94vZmyelNvApgbju9xuPaHqQ< z=-Sx`k#`K8fxRN28Zfw{LkTVRjNLCkwoeh(b;%9?YEWFA4c|5@uC8!m!*klV!}8m* zQhCUP78EHv8)8Jqd#&n%$AbAyt%sa@JB}Cp&|FxvuQud75Ok@*q7Mwm@Eem|r~I*# zi`spOa%UB_Z#4?_kD|m<`jbUzHG69J2Tkb}ChTD~E0O}bkDYr<7h(CWZ-1Tze_da2 z&7O*wSYb`mmJUmOq2|H`#Y*#-^~ZwwCt5#f-G8{N_5IfOV_fRsq7U@dzGz(yLQNC) zV5~iOmr>g@33AVvmn|x>oDRv?&QMYD_E_OwP!L#u#NfTg*9hEIgYaYxhU#Wg^&!6`EDeh49s|^MtCdX72DcMKx z36n4K%=g!~42vmks<71TsCv;_y92`lO$NXoerQ>#b_^76HwgeXxieF8<10+2?6A>v z^Ooeh3iac7DVA|~nYP_}qA(8S@&$$MYS5sfQDV|3-IVL0ZjAwFex*w6_w~tJ5~$sy2*v)V-bP z+^aq}8s9dK-fUBUKDse4Q8lHdFD~(fXDi3X?#FFayZX5cRC8M31yixv5yTQ}o1GE6 zGTUTXR#a?Gt8H>dHe~KJ3FWOP)zM+mfHBl}LcYr{%angQY(Y)~cX*IiQ_bdC|4QirWT{sHskltVw z&b_$Gs}-a1)lq*q(Jg0F_HSx1XS(I|>UeEJ$0X4B2RQ2DGv_+$jhPnxx{MW**JnAQ z?lDLT{AyIx*7S2&cZrc8ZB zdiR(ad(0UA_%eITC)X#wckNQ-x9*WxyN;2KUrtnuMqP4mc_hI3d&~H#_SRj>yMd!7 zEw2-F0r#!MW>=38>eB;}(TQnGN9LqE=<0R{U1qnl$?a}9g8i~4Iq*V!26la0yKn@| zZzmek>W(DV?svAUH=k8s?XHMv`)8s4u6sd|wmY{SOT?k@)TEH_=BJ)I+!1m0==)*A zNOu9YE^TCVPmCFfZ&taj2_qMK8h@6ker05O>7urW#ZylyA$(F_@7`d-As+`oQ)FNG zrgXVe`<8dBzPy)5M3=X31eVt{0?TV0f#rQWQ5`n24Lj}o-SWJ-1q-AJKNaC%x^%o=9c4`nWalf-&go(GD;0cS6K)dTA(H z!mGHqeEF)CtIAi{P;RVPwW8dnl@f6j=|#iKkH2SCMa8N$ciZkQ^Wxz1m3wWg*4S3B zTD{h>eC6Gk-@oQ-Yu2t?gQDbp>(+W#Trl>l7;U>oTw^Qq*?eD-hcVV*CFWmKj(IQq z_sAoE_<<1LiF;y&5Wk9>ViaQffN}2$F)IF%#X>BO$Cc!+EyCp#A_dx;))R} zT!5>Ao;|~L=eJ1)@7N17XpRl3&m>(Ui*~c4Bj?{zv`iX4ZB98ao2JbqGin2~k7%Ex zS+##^8Rm#dt4leTNBcHT?L{RaZJSENmMwbO0v9F!DQ8nlYS*(TVzQe)LRPxP>TIfQ zYV?}y%@!d(I2IAdE+|MiHl)?3=tT)fjQPzJ$Kce1DHj$eEBoZGz1Y!J!>zc_p4 zGQow1aNqZ^c%<+16+UQ}yi9p1H>VX97cOw8nTzCgWLsSdicC!pum6iyPIo;1OwvY2 z-EWgN$z6e$*W}Ba^5tO4rcw)LYO38I*lEJNP21~Iw3$jR>Gln?Mmv7?Op-k~Yl5Tx z&nb9!IO<=M@7a#}H|6{Fj{1Z0{YFRqZ<9Pl_TZ8nTssmY`zm5_Jcmcl^&cx;?7`q$ zBKu^49iMKM$AlW}mW8^9EC15}H=mTh_LN){UjCedm)GRWoATvg%CgdQi@f~>UdUV; z(l*^FulCwi9;;xt2Nzze>=@AME3i*qn7J-dzWQDE$+NDmoR0BVV|=DPc*nSo;~9JX z30RXfe6y)rd(8S;Df{djEHwveLmO*CwFfM?pxOhot~S^M3o`{Sj`G%v%Vg)$kh3ZJ z8JEc3^)PFzfrH|wgSBHG=fYrQ4U+AFX~Gv52pO@s!zZwqKvRsRcR}(VTx3qeHK%T{ z@TCXN#CS&p!Z8YRFE}4?Ck{F4u)HR@5PxF2rBvR18_eQ#2&-(-a~!j8b*rzWV#Unr zF8OA0HrW-6Ba&P{I68x~sS{T?Q~{XNl-IH&)gg7rkP0kKyV~QDaynF8sJy9n2xLsayI`w1oscQ zW(@|h2^kyQH(#!O3kRfjP^FjZ$70a5$q}4o+~jQ9BtK~1%s3ohlE>u5hiLTJ-7d%O zkS{N#Xg@YV{@5mu8`qRN)LEGue>%8OZ5xDv;Sn`Edv`{!rCqt%5i!>f_C&X&^W4tE z*`x12ZBHP#@Vy@F4BY%T^k9D!EaRytbamH+q9=lWTIdyQ7_`5^BYxJH5_G*@--6cz^{?Rd z&H7fn9<1Mo*CRMvP>q7qCFuG9=S$Fa6emp3^%2gPYTUDG_x(W_9d)=e%epm3eJBN$ zYrS=Aj`|l<<~2;hWq5l^gEQGtzayn>t>Fr5BbV5atFMv#Wo_wt1=Hj8DYANLY902C zb9ddZQ;_Yl)crmsnA(ss-uy(0tYJ$21wKA0KOXLI7u5YSXDo#N^;dP|=w4=M-h?YblTaBIQRN_9s)c`n;UiG3-E! ztmL!*GNmJ@P7Z!m$$1ll<&{NVSHhLu5?tP2x9u3#_|mYhNpJZQo>ZD;_0P|L9zMRz zl8(tr7n_S;Dsne`Nz^uZN}UmNagp2Ee)0)9uhQyS{E~Z%p(WL4&OXwT8b0L-eZoRp zhM!UY6p?uKyHh&sbt&~PrKs*?;CX@4g4QdE45`a_`F3 zYu6zkRI|^pzkXf1Ue8;9UwUxrx^!pL#v)+%vwlV#bWK(jTBN?+|# z(4}vq+*)kr$mnL;gF}C=EbPIXy(UQ+64+@BA3CF*FC`v%3}LNsl5atN(NzCj3WjLk zpU}SlE@}HOhZU?fp6RzJxS0u3-o4!8s-z5E1pAWbXuAB%5Nr zW7O9Yagj{xcaaR<+;^Syn=R=Ti%XVig@wi~SE*l5Nyp9ZYbloW#uu(qm#2K`n>v zm?~nnnNWXS=!m55NI~7TH%m?acz^Xxl(zipM|9QP(1` z*RQ1Lm-@O^`E6gyrfnrdi??2bHiWhf-4nmOcCByXN^g1j>J{GJcUeFX!@oOJh>Vwp z3DI46*K-BK8&?dU^k&5{$E_=cKfw_!H7M^sRBBur3cMII=}qquc^zsHG0p=mR@+`* z{N^O};iS#+YITx4yWRRexoNoiW>UJRxY>Nljx6U-ljH}JSf(C4xwPb!Q{l7u;9hml zy{pURc~-vSR@=P%g|_RRUzwOUcZ!(eA3pV)!>2tkeC~IK&r^oqRy!Q`f3LY}rMV|; zs>(MTmcF8Xzcc)Sn%NnCSN-Yf@Z0JfQ}}@Tjw$@Ani?B!)v^nT(YtZ5G%@1E$eB7z6iQ?qOVDiAx$Wu%*r`08m9&a8v+FfTE ztzRY%#o#M;6)M-A2MU8}meI8#TrmD2CGdhd-6Cfko18SdZop_%U3+6EyE@m+#uw+_ zSYfCiFj@&YcO#1uXcg{)!Ud6>*wJcE66UOr9lhA2gwVVYGW3nKj8=zhBP|$-6~V$P zW7@ti(jt}dSmtmLbN~S&vofw*^W17MP1` zn~+gyvRB70vjo<68~iuxKjWR)Z|dkm^@;5pMlZ8eor(8bnqA#Ogv|k0ry;yspKV=C z+W>>U>G;?q%*7WkM*gC<5IG|zz+TWUzlUO6r}UMV6I5%zGR7Z=UonWbFGui`s5*E; z1S?PB3|e(=Hm#`Bas0fsOY&Rw@4t=LmZWGi-I#ynxorMH7tR&l6)Zh9v)^p{wN=z7 zi@F6%JC(G7ql2X;Os7~-^AK>IGPE5@vq2meIH=~ITU_rZ>&x4W zmBoIz#4qaOk=>Nz>j#d;-t7IkaC*>%8nJC)jA#clj)-WkEAT=h@;(=gb~c?Giww5A zK&vUko#wW9+-VkjWKPXoScJuA9PnK$GuZav%@DT~srwSJE%x9#qyF^;`PHmGC*Mj- zEWNp`-a-@_U}QeHW_Rt5?azlp+Z#?Qd&Cl4{_uBR}{&sZr zpQgN<;5TlLbyUf0yyF&&Z_do{iH(PM$@xsV6a5{VZ6`N2K0jJte@|y9a5}+j-t5>o zFZ{%Vk>^MIEcU8zMI3&8(4(7efzvUS8#W&9#Ls6pVFmineL8gYxbYKiot!&m>a>z2 zOYiSpYwcZIb4T5}^x7sf@}rTO9gfM#>(agV;qAWk3a`Ct%AKf;v*Py*Gx0(GuyKaZ zQM1!kyK}C8k2c=wn4E)oX5$U>ObuuBPCZPU+CR`9yfY@RW~brh+MT8Nneab5BNqG4 z*gNezXB%eX#W=&RERCsYn%)^6P!sZu4K>7x(^^piWenUMnlmE4tod3sE7r$9LR-Fn zu)g#}Y_S!WHk3%hriKA>MpSxe8zyJOrLaNt&5ILjqtI6`rtNY030o7>_CvI@-5E3K z^@@cx&4yQMo0a`zcSSLIdfPUFy5$#_*Uxm%$&?*fB=UwaAaL*-dJT88@+A=Jb-z+rBYm>mU)l`LxVj z`r{_w?ECoe@$klUE$1pv5A7FGmaO~tF(`ke%99hhg{@;YPuPfx+pS|zv5m9XCCg?9 zvOjceNOolA1=`}Ady&a8$_mdSbxj;jnn}AVjmoYC?n1L%l$^Ryy-SWzc34V0hF!SS zEDAIk@#Zd&Q@GUx3vLyTdO5N7i@2H$kk#oXoC7C&e;Z{{c^AgHU5JKp+@YiO>(9if zMX)l_8WEY{>XBI#5cM zPW5A4wogSW@!F-1iGVw>zEk+;$m#RDacRDN((7KM@_OFyjpF6(z3Pv9ls)R-odpp} zm){r7xTk3q{>t;}13kL%R(I4;y{AW(RI0k?`Vy+T-Dnm{@|A^;R`nRy->5F>dB&vP z(bMxX?sZtRTXy=c%l@$XcvYLRXGcta5318A?eI0JH_6GedU|%YO$K!jjGv6;_p~{% z-!7c^`zRQ<4UJTNWXwKNeQbJ+t4E#PTko8ROTU&uiYr`TPAf*<-6ZqwaguF%+pmRu zhrV`;*L? zbYvQKMF%XtcE5OD25+=j8ym-{zlq7-8~tX^3|fNowKE9iez#iPjpYQ86+qtU@Q2#z zg3_b<@>%y4R?LHoi8)i=!kl~OYPCFu5SE7O6ud+YDrlZFiQfDZ9Je zD{Ogw-`aanGFo1?di8xanQfMp>nOhnTSYm_Fe@q?4oB~2`SIL8cbdEoJ^mduI^cdb z%<;49GPk6(SbP5DsJ1&Y(>?fAjsEIr-c%`lyV-SA;Mh4Pgc2IC4>{F5N8RhPCig%} zv+J+{qf~=XTt}3m_fW2u1&(ACtqJE>=d~%U} z^J!%g0y&r$n8CihaCNAK@cNJdW z^$jd4)+(8Tm2aQ?Mf$Q*-zpSzZHHeEtUqkC2^Dy;Q3>Tcq^Ja!=#GX4!+YM<^D&4pHVHJ2HEe zGRK6sG-Zz2zF~Gk^_;l=^ZsjAXSDhUdkF6GL@qT2=Nl*Io7Y{9V?Gx5$*{5YkTT!c zV1#YQA%x`Mko&0tC%=L^KAhXc8OvVZs#!8N75^ONin6p^cV3 zG=ABYSRBNG9R_8-3H6a$(;|-JrJ+Ixif7op`%ptvHD#jTFvne>^z>zP9_m3^;LPol zPWo;_jz;((z^E2r$AE_B6&3tiD&%3J5Rp)4)M z@9EB6&Ea$cO7>@k$RKBZo_dlpi{4P zjV?;w5|^sU=P%1!e*VIWiVJ!dre%NAl!N{ANL6|s$$y`o#qw%}^+1>K#Z32=D?5>2 zPA)W~GWX<`+gdU#B^7hg*uG_MOGb%zj&cy0wOfj?z}n~{k+VW|kajO|w#ySu=GGQz zd8e9#b7~JBZc8t9*M_#tYsv6*S{BPTD}7UeAr*n+Y5@I}KL zh@88%=J&jCr?Lyn)DCR7xz=TpKV(6sK`z%^gn&X#;3`}m+EHh3eDED%@Wr5P(OGK2 zik#M7F>T=Jxt0NW->-~E;oxi7Bd9FQH+LMu4QeSeNIPYV{b(7pwan7-yfFCZDm!pw zY?+2Ny$uJWEUw9E9=y{i49hIxOx)~}&mR_8Zx%kpBFM!a$2k{9z$6--uhd*18)|~< zu~Oz>e%z#vb@5o62~W%mcZTiwboD&ESe288mo}J`GlrK?xSAI}dfxX%B{Ejhq~9#T zqNAkgD5JJa#o7;)*MY4)IIWS@KHmnH8Z*#~ObucRrX1_;EovRa-OPkz^eTA&k3DN#OnT{IsLve_fiF4E|@;%;BAB>Y_+y*gY+k&)n(1DQ}X46d_m_l${Um+-8uucB>4uLsf!d zL4n>&1FN~!AhO#reDNZTsWHeE^~Y;#iMr;eP;$zx@(sW%N=t3`7_{1=u7pYXCWHrJ zlcKMRYRkaX)9^uVY)sot@{_^iUxtd*2`K(L5NE0sb;-yCG)s)K z2OmhY$E-`%xa)-pB zADK09XqsI~9xAGj=i&V-;pj1+NvLTGqhPWKg~pO}wD9#9eCEIl!_X#xR}?R_!zA9U zAEV}C*$DdZ`gRn_$K$E|+z9O-ClZyag5 z^};yPt^|2_>v5!A3FpO;T2U9?+t;Um9O-$do)8PcDoGJ-_P#^-Q)L}xI{K=)`}I`| z$Edr{Xf;}2Pg38^!d_Q@o`vY)d+^by{y0nBbVmKv8AK8<$x;_(sYO|8VOGs9^}#F* znwO=zvecPb>h!Fd{puPyC?`w3Axq89Qm@OZX;Mq%pfOphElVAprH;s|*`v;tgREI< zQkEK@rCQ{#1e(mMQw~0zskUdTCo|P!nL(G3vpD20AI?+{W~zV5RA0|jj$sxIdL>i+ zQ>MB*Q{9=VbgHK^G3XDO>efv4_nGQ%Gd-9ELpElrzsyvh$W-evWRD#3qfGS&ndOAWu;(ISK(dFWM^-251_x3Kex7>ir-Ny%65#EKGIIC60cRA{YSy4rTE(%#z)EQo5 zb&NL;wj!_#ElWe?myz=J~9k}yt77s+Cbic7X|Wa`GiQStOaz`-C#w$)=k#l zFkY**FO0V<0dZfG<>)E$Wtx1+lP@#n%WU~FN50IHFB9d9Q@$7zH=({(Mg}`B9Rw_E zc4u9W49fkfnEZW*9^QLuuy>%mFPR%pAjEgH?9mk-t%dl?ofA-FdRsU`dX#Vbm7;uc z=;Y|py7zzjXx%~?ogIs4;IKIwf-U>FpBEYIsO#Ia39>`GMV~MlBfQvyZ05jRgKuoE z(Kl2ZYe3|*4A;hSt<0K=(2d}%>Dss8EQDFi!jV2J*RabTynpJz*8&moEfX@8=)NW= zzkjMc@(l=v&`%0kO&je$B8rNOo<<|L%@@0|XSct-J!JD+N@e?hX{a=?Gp;Jv<~QqK z5vTHWjGQtC5h?nhBIU$_Vg$mYJ$pp%yS`NApz^8~Co|0#Yri$tA3Nvp$#4o{NkcZ- z%C@gD5-CL&=Tbe_HZIzHXn*j5q=*dY__YC<+9bvGmm1fr=d~%y!CIT4)hcVw_bWwj zU=aEe6c0Yv+&EKS$!A+H*W8$D)tVdS5-!!;c-NX-h^em27U*GW>(AO8#4s zeA)2WlOQis=NcXz?T$KmyVDyUgRVE6d*z+%W-e8 zowaW%Zv{(VtqlcB-?l3cBq^0|DC__7U{56COWiOl!G86eM7Y!;9_tNT!1Wi~;ooWv zmDlPGmA*?iRH7NQ+4Y7HZ635p$`;FvOSf3|O_zPH<#N2$n-(nni@rk5bCQIxD}Yvt z2kVR6-($zn$hpSNaeCvXz7Mh219OsWavgoQ>KswFjzjiIbCSHyz9v%qkX0_~+z*6@ z=!*^~2G)Nd)|vHh!C9$TgVf-xVR#!BoHYt>BZ9Ni@HVP2xc=4J=HU9b1I=k0mL#ax zpG6TtyZr}V7`HUql|cyw-cEV6HLU*^cqgSHUOuW|$D=59qOP;3Sa}r@i^@S9w=z6S zIVhtuT)7T^s(t62I2&FD$d`DVaxl;w7e16b&Ob9MaP znycb@goT+A7G}&mxH0@Ylv%Wv60FS4~h~K5lrn?ow#%vC*+~WLU)316lR<5m}HJi#6h`L%*DJFaq4z~Z=2-( zsqdoZs52p)&K|TB$w-~2o^sURV8zQ#@}(zXyVZ(oquylzU1+)zFm$pUHATKmlP`Jl zWu|Eav>a6Z zBrA4`EaGEh&<>@A??u0&{1z>^r76!xgDkX;EYU5fZCY%$*O?JK?>wNF&{43lV2i&e zw88tUrs95%a`m@G)l{Q+#Q%5O(k5J z%CSw#u1%g|<(0>+0>S^OLMs8EH%99MFi>>lBV^R(2qS&$WfE}yDW!d|7{i`o$$f2HLI%I;GJ029a|Y+)g9->*MxO8E%x8z8|IcV zHB(|79)Hs2Qq?hR^GtQ@u(q}Y8OJzj>a)ZhO1MCA&%M6 zY#wzzGP6BbX`f^yv*n{t5y>q6ZiKOFgr#~!+^c9(6&_>4KujJc0w%==-+ZI5N#{$4>LFMu>2dv_Tk3EJ9CyHDZh972$Y1 z+&e)S6HJWa`LBZAiB#Bqn2Iy_si0Vw!TG?TpP}w`H|cQ5QaTBqV5>FvFF9MX%TI`tM4)N zU&U88$EkHgQPO>E=;pY#e;V4$gDwS=Q*l8WF~cz_H7?OR=(a$YvBH8Vvg^COu_!Th zC-g4H@%Wj9+}H}l#A3g8C%l4@@rjO_w8X?$%!N+$o~sVY&IoqpDtpZ`V~IuI5pnXW z?A-0#yT#PmGNJ+jM4f-I>_k<|PFd+PSJ{X2?g*kGGrG2~5FPLT6Ta+Hhjba5AB_CL zQW4wm2aBOuS>K7lo$A@s=oV|-Y^Zj1v!Bz{nt^I zr2je&tP#o{<&StcQKWdgK@@Mdh~fgb>KKapn`&3rVvjcP+=!ua#MW7+j^p^X2CUlQ zt)ngSi}q6+)^u&i@7_?^lf4)59ZO%)`qS^$e^ZMD!OUj_plVxl4Sho0n`XN~=8}BTZM}`3DFnJ^4g>X~U6p+-P^;QBS@YOre~VPj3ix z=B@j>j0stduc0#@9w-i111u*z%M;F%b+|9epTTcA z5dEBuTd?q%@w&vHiMZv6Ku<(Oz%?up==q=SR)?V@ktw}YX`Ulbt+28&{9SGNe#3k% zR2B>LKOl=7*aXCy`LC9x9ppx*Snc&je?`P+`9yP``fQg6r84>TBO)5h?i=sAZ$T8^ykpSt=DL0+isyQnz- z&;GkBnq`+gLzP$6F&$ou(xEN3|GAxVUm|5qek2 zCj|;e=NE|3RkE){6w?+&VZ~CE=GL+>eL0x_s?5tpN9BwUFFYze>7~eZw5uP=Z9^~G zzHOU!T1`LEHtBS)M7y#F7iR=OcPE6=&j{z=bOh{PKesnO*4&#Pn^N0s52guGv%j{f z_JGoXt~=8aF@*!DK^SC=drIH0w7t=({$@bie{`yM#kalOsXi3nwyP6&MGK0~%%pHTJ?!KK71MI#3`oy77WsWI;lDsTbin{;Mn{rC~E(uy=Yl;B?!!I?;2xN^D5{ z-TGVFDvk0+(}U9shjx->S&8j{Z?rtr0?o;ey08P~>JR11U**ej$EL7F-H_;byv@VaH)0Fw>faYzmJzRS;|J$S}^(4;50Wfvo~q|n#bCM(`pYoBf;6ONqhVwgR`}Y z3;zJgp{^OwukJ#tGjGO%+9zN^5y#}T&IuLQ$tZlBowCD%f3zOImMWwB5jYu(1;%L+ z_-fVw!%H*6yK3K%eHH8Cg}uI7)Ft9=gQ!c!TaBo*;;mMA(rcf$2kkS2y*70g4z{#Z zJhLS2eTVu^oV+nLRttM%qLwd+kM3zb>)tLe&aLvoD=*F&TIPMEo_W8)s)RgkWsg72li>iX*}aU?l+)e5GaO!jAJLb z2C*$?J&G%$sB`De{l~`wO$lRFkI(4-iKhZF?MvJK@NR>z6i>79mXc@E9W&CloD`r7fO@8b{Yq~pM>b;m_8uZw_a!XD6VR=qB ze#Nfdkf;ti>}(J846B$SyMCg#p!Sf1f$Et<$n5xb3Ygd%_c5mNb zo!XTkdyL10Z)^~Ev~4^Q>gtvUgnNN@BOE@qF?VdVLvsIq*Nae>mTqYoe#t)3o8P-! zpXl}p(LT|g6M|FQC&)h0of9tICmPKGxTt08ZKN^A+9tiZ?{@=`M?ll5)?j+npp_9D z1fr?cgN9A>!he!I2f7k|RfW>(QQ@fXMk}fo(J!Cd&{y0wYn?cwWnHcBuGW@ksj#c3 z-o3YM&8p@7J3%A*cZC+&Z(HGARVh0^=V-0#ZKaW%XoK^@i1t9lb7kUmxfZ>};vBR& z=b+6wC)(zGUg0-Kwms+cHW!~a3gu#q7?{)BY}~(Ge0~El?iaW;$jwz39@aVb;OlkP zZT)xP6?>Fp#~Am$Jw=!*@SvuX4!QTy1M^)ObFAl~oqM0{zP53|*amSsf>e#+0gbO; ztKKm{9e=RvRJeNvjL^Q;`*fk1Ywx+I41LGvp~J5CUax%4kXW)@ALzh)?@4v;JvmVb zb7Phe!|Uxr*dD`6#vQ|jxcX=KH0B!^fool{xqk?Awh~hRiU!?J8!g@!EG{=rjX!eH zp4OtgZTIM5P@vl-@-W}LOi#kzZkH|Ec-if;eS-H+ykQ>KCwII2;U&9W%JvXEy)O1| zv->5s?9+6=#AKhn`(@{Z&(!_0aKWTK-l0#Ml+eC+0$~$!fnf*E--$gH2!ED+HbaZh z9YxCu8r7$dR3QAsh>A;OWVG`>t-&}WSlT1&D^&A)*xNaVSRuPSY9}3@$T48L-;Bky zr5VuGt8dZ+?=Hr)@diiTNr(D(k%|=Uk$#Q;=up3B^0b}6HS$A;qyD%9HFbY=2m>l~ zo6SPB*tFtcv$+b_Cv6YcBi|aF8g^(;$7wdlCsqlBWhJ7P#r!^=de9@wvD#CE^a9vF zMhjpyS1f?}*2tDMbO%De!e@m6i&5V_;zcEt&niQX4b8O&!|&sP0T_GZJMva+ zud5dI$aB|i5cSA&*VTx6(Wa<~Sj7iGU^QgwrkR>a%h= zM-TT62C;m+Liw7t{=2`@d+C!A6#g}~d%bJ##zW$8z34*V5i;>L$it&YX>BUdg7&a1 zihwSd^H;}nVn9iQ(TJz`eZQdSm2(}b30NW&cmmlAs+QpU@%h z3u>X-9POa?Ni9@02zNNwLiOL&HEz7ME$3Y8(FI-Owq~O=_ZhmzZOy(y*SNGxc8x0x zrmKJKEct|PanF4IZgDrril3XTRa2Ju6Z@)xoV%m_#%12K&RpFQPCH4#RrQL|9~M8`3+N|y>5qm zEd24|t#~v%VhxH^MHUD|J;xwmyqPitv+>zc&YQq11(r~Qux z)+Zy9MC%q97sf*5YB-+fcj0unFK9?w+(tv zDd2pTxs0D{F4O0lEADg6W&K=p**@1?(?7>tSykfm%q2e0{>l=cXMbgh%kHo4n=gAr zU2da#CVj#zLYOZ8&tU5P@8WS64ViA(Bd+w{BGbkHoj-k{x!-@r!cX;I|0PtQaM<@B z{@%=|`LB0={(YiIL?HOyC}OZ@V})5*M4T8P;zfc;6iFgkqzJ1RC4cbh>>EH7%kF7y0D21akUsDGDViKi)+NSVyqY^#)}E!I^hr#MYeE?>%|S?MsbtK z5jTrl#3XU6m@IO|6fspy6VpYR__A0oR)})3Qrs=RB36m7im!>);vTU^tQGf)uM02s zs!#YurC2AvA?_336eVJbSSm`zGV!I)HUHm<`^C4!dhvj$5)X=Ri-7o!_pcuf36{Hyq>cwE$ppNV?$ zg!sAmh4`iTmH4&TC^m^F#Z%(n#BaoA@w9kG{8nrczZ1U~|Bfu=R`IN86n_xUiEU!L zXc9Zb^CBc(5HE_IqFL+`yTu>HOX5$WMZ7Ft!P(U+_KJPtKg6HKtKv1WU%W2f5C_Cx z#GB$RaZtQ14vE9!9dSgwE8Y|D3stm<4@6iT6(5R^#9zfRaa^1bC&el8v1k_^qEnm} zUE+-B7H36|h={+1BOp)A5HrOrFQ?q$}j1U;J4P%Zx ziJF4JvdJEeo7=mLh@08=O{2P8nA4mGwq&7TZG2R>p{sI)HbjU_tEFOP#$mBw- z&uRVbg!a(;frx}FQXjxGF|?-c#!1F>3l@o(;0S)QvCCK($ypzxeiu)jGHpSp3p_!i z_*t8fN3RXBsvY@=*pgG?!5UX#A@ZRGamr5o83$MR0P0LoW2r^x6&31b7&%|kE&Jsk zDo~EimBklllYGVLahb#*{=aXPS=N6wZ69aN{;(KNRKb%(mO1LC4sz7b804s% zH3+*c$*pd|Gn{dlIO=B&Qr}DPSUUe`#3NkrsD9%!Ni7+8jc>`&9?~ykm9~s)$x!ww zcvO@6${>upt|g-?5?^7)M;wAOItXKa*E{A+|1o%`w)!t}Oy5#v2$){S)7#Z7t=WYV zY`^DAO-DQ+9u)I4H2tEXA|noeDGDJ>BU&=j@jO60tZhtOp=y^Kusy@9ycIn=8Z*rD zX@O4Vt)hmJX1Ds`dy zeUDr}#2&2g5kBc})AlMx>7Tcy2{c#A0Nrs~;7(HDbRrsj5V?b=CJxwQtbV>FW1jzD z;Izs6hCau<@Ch{5VU%1H9x;a-8WtYw#Zx)u-}~5ccFTNh!ary~7^6OOc9FJLafmRg zj8W^)%D*~tex2d}_Y;FZ__rb;gB#pszOS5n%JQu?;lfj=&l_;pny;XJQ9hphJ1&mlK@yW#%lH+n)IG;z0NptG~14%fS2>eNAKlZa{iF)k_7wM$?y zZPp+e4u`XR>Y$2Y3$&)=MP}J}eCr_X47bR;C?ZIUWkYk`pi733PP|MAsf=nT4WAW36lwV9^3Ir`pJIp^4Iiu7k1NvCwC%>D46)t6_=N4wz((}j?uId0&sN2> zWHcJAYE|Nv;Vl`CpFK2an`;mr3^)f@xa?T;dAt@kx!#)_?s(|@oPli5F!`Q47g?`= zH{{;#^W?hm@fkz-?c4$W31}D9;kKF(u7Q`at($ENaA}K=?h;(+Jc}2J7d_$42q(7X z#`&(grKRGDT$}gt+y~Y@c5cT#s-7~0Yj6nm-P>#*;)hm5&h3~rc;v6V?_8tpkV3R) zHr_g@P@RnDsXA-)J265FhPqY{hWZg6`>a1UI37!ueH;EPkB|v@)z5E9 zZpmnSr$uGg_VEK{Ql;+N?dQ?vJ}F`YQM45u5%SwpxqEWE;{!Eu>OgF5@n1*eBRIYQ`P z9gQuQeQ0_!ESd5M!Fr)r)_ED01nitGla&)K8DVo{MUuL5fb1Bv91l$QtzBzFJjQ*t zGVk4f`4sgETq~nb#MJ&Ws`lgZPosv^>;dY)cKn?FOx$Oa)bs)ASj@~>@(&Da|7POS zdw03^_n(&gyGtq<`wiVq;IM+{Pn2{{P~5I+TRM0 z-N0AaD*RvWT_gEN1rW+nc5W51oY^zy&W|prF#4CY^q=#Ue*=HmYAq(#){rcfz@kJ@s)BscyQH9+bZ8R723^8&bqn`E4OM*g|BSQa=8fwvuDho zuP>uO>!q&$@I7Vt1J7&Z1PkZgc_j(?$D!p^i`Ks&^n!YFBR>9Ytkv=OLxW6t`t=T1IX&;V1XpC& zAoU}e`PcK5c=Db8IT{!eDlT7*@E;sJYi;hC^Y6UVcI}t_t5&bDU4Q+}x7^^k;rg2< zO_I-SL{%yOQQ!*`c;t~sOb9r;HR;5I2o+Cyb%PKu#}xiVh)mNGJRs+1Np~Yets?Hl ze-`4`Nv8^hxId-m*C>Y$D#i0|#tqgAz7u4@x9V*F5-qY^>h2i*e5g9ze~c_2|E71$ zMdjlk$T596g>yHmzRptT3c!WxT=}fz?e-z(O1JhQeWhF55Vv~Ti2FnD&7uQOaJkgY zLY8jPCMyfHnM2l;|D&T$uG%83jb0A64Y{ZsY+}vl7k0q^ zk6N(aS}&iU{K=1BF8Tr=zbsGl;)@=KY|7S;?86`TJrG%YyfN;2vSvhPvOn&9y0Ljd zair2LAN^XTSBv_Gc$O`)ER`{vjnl4DL-?a?vO4vXpLZJg5pYcy> zjk!2>WcA3)Huhg3;^c~RT{eQ@igR5yg5ipDT{hz6igR5y;^c~RT{hz6igR5y;^Yc* zT_NJ+N^@O4;^c~ReV+Ywg@}_i^6xBNI)>?T5hwSif5I$`IQbuS)B6He_HQBHfDtE* zIAO%ee_zZIaxb40I{XD(dALXlP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun z0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP z3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbF zC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epy zpa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+ zfC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O z0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC z1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo z6rcbFC_n)UP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)U zP=Epypa2CZKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZ zKmiI+fC3bt00k&O0SZun0u-PC1t>rP3Q&Lo6rcbFC_n)UP=Epypa2CZKmiI+fC3bt z00k&O0SZun0{@R4IuHN=0002;e{F;W2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J^Xw(18E| z0001x|7#;8IB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yRZhYkb)0001h{9hX(!GQw@4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^` zz<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!K zaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB) z95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c z2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*= zfddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede z;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQq zIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n? z4jede;J|?c2M!!KaNxj!0|yQqIB?*=fddB)95`^`z<~n?4jede;J|?c2M!!KaNxj! z0|yQqIB?*=fddB)95`?QJ9Hob00000%HELo6~W=n(gZSAe*LMS|acP DjOCBH literal 0 HcmV?d00001 diff --git a/src/Makefile.unix b/src/Makefile.unix new file mode 100644 index 0000000..2f65ea2 --- /dev/null +++ b/src/Makefile.unix @@ -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 index 0000000..ce995b5 --- /dev/null +++ b/src/Makefile.w32 @@ -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 index 0000000..a4867ff --- /dev/null +++ b/src/apps/Makefile.unix @@ -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 index 0000000..1deffdb --- /dev/null +++ b/src/apps/Makefile.w32 @@ -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 index 0000000..07d771f --- /dev/null +++ b/src/apps/hello/Makefile.unix @@ -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 index 0000000..369b9c6 --- /dev/null +++ b/src/apps/hello/Makefile.w32 @@ -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 index 0000000..330dedf --- /dev/null +++ b/src/apps/hello/crlf.asm @@ -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 index 0000000..f477f8e --- /dev/null +++ b/src/apps/hello/hello.asm @@ -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 index 0000000..3ae4d08 --- /dev/null +++ b/src/apps/hello/hello_.asm @@ -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 index 0000000..8916479 --- /dev/null +++ b/src/apps/hello/hello__.asm @@ -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 index 0000000..dc8fabd --- /dev/null +++ b/src/apps/hello/test.c @@ -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 index 0000000..b268990 --- /dev/null +++ b/src/apps/hello/writechr.asm @@ -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 index 0000000..7571729 --- /dev/null +++ b/src/apps/hello/writehex.asm @@ -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 index 0000000..586b3de --- /dev/null +++ b/src/apps/hello/writestr.asm @@ -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 index 0000000..4b669c3 --- /dev/null +++ b/src/apps/pcomm/Makefile.unix @@ -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 index 0000000..994bad8 --- /dev/null +++ b/src/apps/pcomm/Makefile.w32 @@ -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 index 0000000..85ecd7d --- /dev/null +++ b/src/apps/pcomm/cbreak.asm @@ -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 index 0000000..0ccdbb5 --- /dev/null +++ b/src/apps/pcomm/commands @@ -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 index 0000000..330dedf --- /dev/null +++ b/src/apps/pcomm/crlf.asm @@ -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 index 0000000..359d292 --- /dev/null +++ b/src/apps/pcomm/date.asm @@ -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 index 0000000..a15c65e --- /dev/null +++ b/src/apps/pcomm/dir.asm @@ -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 index 0000000..ebccc4e --- /dev/null +++ b/src/apps/pcomm/erase.asm @@ -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 index 0000000..c88db9e --- /dev/null +++ b/src/apps/pcomm/exit.asm @@ -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 index 0000000..8cacbc4 --- /dev/null +++ b/src/apps/pcomm/genhash.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * @file genhash.c + *****************************************************************************/ +#include +#include +#include +#include + +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 index 0000000..14593b1 --- /dev/null +++ b/src/apps/pcomm/genver.c @@ -0,0 +1,19 @@ +/****************************************************************************** + * @file genver.c + *****************************************************************************/ +#include +#include + +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 index 0000000..0b9b695 --- /dev/null +++ b/src/apps/pcomm/history.asm @@ -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 index 0000000..c9c2a41 --- /dev/null +++ b/src/apps/pcomm/pcomm.asm @@ -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 index 0000000..51fe65d --- /dev/null +++ b/src/apps/pcomm/time.asm @@ -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 index 0000000..57197f2 --- /dev/null +++ b/src/apps/pcomm/type.asm @@ -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 index 0000000..9f89487 --- /dev/null +++ b/src/apps/pcomm/vector.asm @@ -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 index 0000000..b268990 --- /dev/null +++ b/src/apps/pcomm/writechr.asm @@ -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 index 0000000..4b0402d --- /dev/null +++ b/src/apps/pcomm/writedec.asm @@ -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 index 0000000..dd07263 --- /dev/null +++ b/src/apps/pcomm/writehex.asm @@ -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 index 0000000..161b82e --- /dev/null +++ b/src/apps/pcomm/writestr.asm @@ -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 index 0000000..5957544 --- /dev/null +++ b/src/apps/pcomm/xmalloc.asm @@ -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 index 0000000..77c9b06 --- /dev/null +++ b/src/apps/pcomm/xstrcpy.asm @@ -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 index 0000000..308b6fd --- /dev/null +++ b/src/boot/Makefile.unix @@ -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 index 0000000..48a3baa --- /dev/null +++ b/src/boot/Makefile.w32 @@ -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 index 0000000..19e4d5d --- /dev/null +++ b/src/boot/freeldr/Makefile.unix @@ -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 index 0000000..849742c --- /dev/null +++ b/src/boot/freeldr/Makefile.w32 @@ -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 index 0000000..01c86d7 --- /dev/null +++ b/src/boot/freeldr/bootsect/Makefile.unix @@ -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 index 0000000..73b2aaf --- /dev/null +++ b/src/boot/freeldr/bootsect/Makefile.w32 @@ -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 index 0000000..39796b0 --- /dev/null +++ b/src/boot/freeldr/bootsect/fat32_chs.asm @@ -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 index 0000000..71ec3a6 --- /dev/null +++ b/src/boot/freeldr/bootsect/oldfat.asm @@ -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 index 0000000..3afab38 --- /dev/null +++ b/src/boot/freeldr/core/Makefile.unix @@ -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 index 0000000..7141a47 --- /dev/null +++ b/src/boot/freeldr/core/Makefile.w32 @@ -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 index 0000000..d1c4d63 --- /dev/null +++ b/src/boot/freeldr/core/bootstrap.asm @@ -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 index 0000000..33916fe --- /dev/null +++ b/src/boot/freeldr/core/config.asm @@ -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 index 0000000..b715115 --- /dev/null +++ b/src/boot/freeldr/core/crlf.asm @@ -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 index 0000000..21e8920 --- /dev/null +++ b/src/boot/freeldr/core/disk.asm @@ -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 index 0000000..40f6dbd --- /dev/null +++ b/src/boot/freeldr/core/error.asm @@ -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 index 0000000..73ed6c9 --- /dev/null +++ b/src/boot/freeldr/core/fat.asm @@ -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 index 0000000..e4cd3fb --- /dev/null +++ b/src/boot/freeldr/core/fat.inc @@ -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 index 0000000..fa437ba --- /dev/null +++ b/src/boot/freeldr/core/file.asm @@ -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 index 0000000..38ca233 --- /dev/null +++ b/src/boot/freeldr/core/freeldr.asm @@ -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 index 0000000..0e5c2c6 --- /dev/null +++ b/src/boot/freeldr/core/int21.asm @@ -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 index 0000000..c94b283 --- /dev/null +++ b/src/boot/freeldr/core/ll.asm @@ -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 index 0000000..f3d6e50 --- /dev/null +++ b/src/boot/freeldr/core/mangle.asm @@ -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 index 0000000..4e28044 --- /dev/null +++ b/src/boot/freeldr/core/mem.asm @@ -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 index 0000000..36b99c0 --- /dev/null +++ b/src/boot/freeldr/core/menu.asm @@ -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 index 0000000..7d054e6 --- /dev/null +++ b/src/boot/freeldr/core/screen.asm @@ -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 index 0000000..75583f8 --- /dev/null +++ b/src/boot/freeldr/core/search.asm @@ -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 index 0000000..2b3988b --- /dev/null +++ b/src/boot/freeldr/core/vector.asm @@ -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 index 0000000..e3db99c --- /dev/null +++ b/src/boot/freeldr/core/walk.asm @@ -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 index 0000000..b268990 --- /dev/null +++ b/src/boot/freeldr/core/writechr.asm @@ -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 index 0000000..bd97d47 --- /dev/null +++ b/src/boot/freeldr/core/writedec.asm @@ -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 index 0000000..2b0eba7 --- /dev/null +++ b/src/boot/freeldr/core/writehex.asm @@ -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 index 0000000..a849e2e --- /dev/null +++ b/src/boot/freeldr/core/writestr.asm @@ -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 index 0000000..cb56c1e --- /dev/null +++ b/src/boot/freeldr/core/xmalloc.asm @@ -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 index 0000000..1443176 --- /dev/null +++ b/src/boot/freeldr/core/xrealloc.asm @@ -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 index 0000000..2cf568e --- /dev/null +++ b/src/boot/freeldr/freeldr.cfg @@ -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 index 0000000..8cacbc4 --- /dev/null +++ b/src/boot/freeldr/genhash.c @@ -0,0 +1,101 @@ +/****************************************************************************** + * @file genhash.c + *****************************************************************************/ +#include +#include +#include +#include + +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 index 0000000..d5fda1b --- /dev/null +++ b/src/boot/freeldr/keywords @@ -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 index 0000000..b3b5803 --- /dev/null +++ b/src/boot/freeldr/libc/Makefile.unix @@ -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 index 0000000..d4f502c --- /dev/null +++ b/src/boot/freeldr/libc/Makefile.w32 @@ -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 index 0000000..27bcbed --- /dev/null +++ b/src/boot/freeldr/libc/stdio/fclose.asm @@ -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 index 0000000..7ca588d --- /dev/null +++ b/src/boot/freeldr/libc/stdio/feof.asm @@ -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 index 0000000..32dc079 --- /dev/null +++ b/src/boot/freeldr/libc/stdio/fopen.asm @@ -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 index 0000000..a59e3e1 --- /dev/null +++ b/src/boot/freeldr/libc/stdio/fread.asm @@ -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 index 0000000..d165740 --- /dev/null +++ b/src/boot/freeldr/libc/stdlib/free.asm @@ -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 index 0000000..bebd0ec --- /dev/null +++ b/src/boot/freeldr/libc/stdlib/malloc.asm @@ -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 index 0000000..2e43b97 --- /dev/null +++ b/src/boot/freeldr/libc/stdlib/realloc.asm @@ -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 index 0000000..ec8cb39 --- /dev/null +++ b/src/boot/freeldr/libc/string/memmove.asm @@ -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 index 0000000..273730b --- /dev/null +++ b/src/boot/freeldr/libc/string/strlen.asm @@ -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 index 0000000..578342b --- /dev/null +++ b/src/boot/mbr/Makefile.unix @@ -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 index 0000000..2fb6aa3 --- /dev/null +++ b/src/boot/mbr/Makefile.w32 @@ -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 index 0000000..33374ca --- /dev/null +++ b/src/boot/mbr/dosmbr.asm @@ -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 index 0000000..8be5e8a --- /dev/null +++ b/src/kernel/Makefile.unix @@ -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 index 0000000..d444a13 --- /dev/null +++ b/src/kernel/Makefile.w32 @@ -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 index 0000000..28231f0 --- /dev/null +++ b/src/kernel/bootstrap.asm @@ -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 index 0000000..b715115 --- /dev/null +++ b/src/kernel/crlf.asm @@ -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 index 0000000..64fba99 --- /dev/null +++ b/src/kernel/disk.asm @@ -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 index 0000000..0018abf --- /dev/null +++ b/src/kernel/divide.asm @@ -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 index 0000000..cfe6434 --- /dev/null +++ b/src/kernel/error.asm @@ -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 index 0000000..7053b0c --- /dev/null +++ b/src/kernel/fat.asm @@ -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 index 0000000..e4cd3fb --- /dev/null +++ b/src/kernel/fat.inc @@ -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 index 0000000..f728c17 --- /dev/null +++ b/src/kernel/file.asm @@ -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 index 0000000..36a760a --- /dev/null +++ b/src/kernel/find.asm @@ -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 index 0000000..bff6bb3 --- /dev/null +++ b/src/kernel/int21.asm @@ -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 index 0000000..b422cbb --- /dev/null +++ b/src/kernel/int23.asm @@ -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 index 0000000..aa8a9f8 --- /dev/null +++ b/src/kernel/invalid.asm @@ -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 index 0000000..dc23c0f --- /dev/null +++ b/src/kernel/kernel.asm @@ -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 index 0000000..ba57b6d --- /dev/null +++ b/src/kernel/kmalloc.asm @@ -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 index 0000000..82d3ec0 --- /dev/null +++ b/src/kernel/krealloc.asm @@ -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 index 0000000..027ff0a --- /dev/null +++ b/src/kernel/mangle.asm @@ -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 index 0000000..477a423 --- /dev/null +++ b/src/kernel/mem.asm @@ -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 index 0000000..6e76d5a --- /dev/null +++ b/src/kernel/prog.asm @@ -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 index 0000000..fac9ebc --- /dev/null +++ b/src/kernel/query.asm @@ -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 index 0000000..4ce90fc --- /dev/null +++ b/src/kernel/search.asm @@ -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 index 0000000..d0bb687 --- /dev/null +++ b/src/kernel/vector.asm @@ -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 index 0000000..98c1c4d --- /dev/null +++ b/src/kernel/walk.asm @@ -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 index 0000000..b268990 --- /dev/null +++ b/src/kernel/writechr.asm @@ -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 index 0000000..bd97d47 --- /dev/null +++ b/src/kernel/writedec.asm @@ -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 index 0000000..2b0eba7 --- /dev/null +++ b/src/kernel/writehex.asm @@ -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 index 0000000..a849e2e --- /dev/null +++ b/src/kernel/writestr.asm @@ -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 index 0000000..a477ba8 --- /dev/null +++ b/src/lib/Makefile.unix @@ -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 index 0000000..08f1adf --- /dev/null +++ b/src/lib/Makefile.w32 @@ -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 index 0000000..f057cee --- /dev/null +++ b/src/lib/crt/Makefile.unix @@ -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 index 0000000..174fa3b --- /dev/null +++ b/src/lib/crt/Makefile.w32 @@ -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 index 0000000..7b22d2d --- /dev/null +++ b/src/lib/crt/crt0.asm @@ -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 index 0000000..2bb0937 --- /dev/null +++ b/src/lib/crt/ctype.asm @@ -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 index 0000000..165b10a --- /dev/null +++ b/src/lib/crt/include/stdio.inc @@ -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 index 0000000..0ec7ed2 --- /dev/null +++ b/src/lib/crt/include/sys/fcntl.inc @@ -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 index 0000000..27bcbed --- /dev/null +++ b/src/lib/crt/stdio/fclose.asm @@ -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 index 0000000..b67f574 --- /dev/null +++ b/src/lib/crt/stdio/feof.asm @@ -0,0 +1,97 @@ +;****************************************************************************** +; @file feof.asm +;****************************************************************************** +%ifndef HEX +% define HEX(y) 0x##y +%endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Includes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +%include + +;****************************************************************************** +; @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 index 0000000..a0eb61e --- /dev/null +++ b/src/lib/crt/stdio/fgetc.asm @@ -0,0 +1,144 @@ +;****************************************************************************** +; @file fgetc.asm +;****************************************************************************** +%ifndef HEX +% define HEX(y) 0x##y +%endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Includes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +%include + +;****************************************************************************** +; @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 index 0000000..64efd06 --- /dev/null +++ b/src/lib/crt/stdio/flags.asm @@ -0,0 +1,155 @@ +;****************************************************************************** +; @file flags.asm +;****************************************************************************** +%ifndef HEX +% define HEX(y) 0x##y +%endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Includes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +%include +%include + +;****************************************************************************** +; @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 index 0000000..b4ad7e9 --- /dev/null +++ b/src/lib/crt/stdio/fopen.asm @@ -0,0 +1,313 @@ +;****************************************************************************** +; @file fopen.asm +;****************************************************************************** +%ifndef HEX +% define HEX(y) 0x##y +%endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Includes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +%include +%include + +;****************************************************************************** +; @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 index 0000000..4e60c45 --- /dev/null +++ b/src/lib/crt/stdio/fread.asm @@ -0,0 +1,214 @@ +;****************************************************************************** +; @file fread.asm +;****************************************************************************** +%ifndef HEX +% define HEX(y) 0x##y +%endif + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Includes. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +%include + +;****************************************************************************** +; @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 index 0000000..6b45a0b --- /dev/null +++ b/src/lib/crt/stdio/fseek.asm @@ -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 index 0000000..f50a7c5 --- /dev/null +++ b/src/lib/crt/stdio/ftell.asm @@ -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 index 0000000..d165740 --- /dev/null +++ b/src/lib/crt/stdlib/free.asm @@ -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 index 0000000..bebd0ec --- /dev/null +++ b/src/lib/crt/stdlib/malloc.asm @@ -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 index 0000000..2e43b97 --- /dev/null +++ b/src/lib/crt/stdlib/realloc.asm @@ -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 index 0000000..ec8cb39 --- /dev/null +++ b/src/lib/crt/string/memmove.asm @@ -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 index 0000000..b313bb6 --- /dev/null +++ b/src/lib/crt/string/strchr.asm @@ -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 index 0000000..946f5ee --- /dev/null +++ b/src/lib/crt/string/strcmp.asm @@ -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 index 0000000..6e93188 --- /dev/null +++ b/src/lib/crt/string/strcpy.asm @@ -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 index 0000000..53159bd --- /dev/null +++ b/src/lib/crt/string/strlen.asm @@ -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 index 0000000..f45c4c1 --- /dev/null +++ b/src/lib/crt/string/strrchr.asm @@ -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 index 0000000..7a99176 --- /dev/null +++ b/src/lib/crt/udivmodsi4.asm @@ -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 index 0000000..1d7c699 --- /dev/null +++ b/src/utils/Makefile.unix @@ -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 index 0000000..bedc723 --- /dev/null +++ b/src/utils/Makefile.w32 @@ -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 index 0000000..31b073a --- /dev/null +++ b/src/utils/binutils/Makefile.unix @@ -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 index 0000000..3022f72 --- /dev/null +++ b/src/utils/binutils/Makefile.w32 @@ -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 index 0000000..d7ae5cc --- /dev/null +++ b/src/utils/binutils/ar @@ -0,0 +1 @@ +Subproject commit d7ae5ccfda2892d7804ab86039a740547c089158 diff --git a/src/utils/binutils/as b/src/utils/binutils/as new file mode 160000 index 0000000..1c5f2de --- /dev/null +++ b/src/utils/binutils/as @@ -0,0 +1 @@ +Subproject commit 1c5f2de0ea49b930fc16bbf187b1adb64cd01832 diff --git a/src/utils/binutils/ld b/src/utils/binutils/ld new file mode 160000 index 0000000..ee1bb0f --- /dev/null +++ b/src/utils/binutils/ld @@ -0,0 +1 @@ +Subproject commit ee1bb0fe4d5e457480ff4ab46fd1f9cf40a1cfb2 diff --git a/src/utils/dosfstools b/src/utils/dosfstools new file mode 160000 index 0000000..2b218a0 --- /dev/null +++ b/src/utils/dosfstools @@ -0,0 +1 @@ +Subproject commit 2b218a0bd719edc90f0e6168b8c55c909ee67703 diff --git a/src/utils/parted b/src/utils/parted new file mode 160000 index 0000000..d0bd265 --- /dev/null +++ b/src/utils/parted @@ -0,0 +1 @@ +Subproject commit d0bd265427872bba3161c4d1b4a73b8058d0cb9f -- 2.34.1